From 42ec8191fd60f5fd8808f31598c0207077c907e8 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Wed, 16 May 2018 22:13:59 +0530 Subject: [PATCH 001/392] Revert "dm: use bioset_create_nobvec()" This reverts commit 3d8aab2d2cca2dc878e396196d07889129440798. This revert is required to support request based device mapper. Change-Id: I41e5192d0e5a3415541ae505642acde04bd5da22 Signed-off-by: Neeraj Soni --- drivers/md/dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 256b515101a8..adc2783761aa 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -3091,7 +3091,7 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, u if (!pools->io_pool) goto out; - pools->bs = bioset_create_nobvec(pool_size, front_pad); + pools->bs = bioset_create(pool_size, front_pad); if (!pools->bs) goto out; From b4598a90058d7a44fd986d1a47e6998afcdb0621 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Mon, 14 Aug 2017 15:53:45 +0530 Subject: [PATCH 002/392] clk: msm: clock: Add support to use Max uV for cpu clocks CPU clocks and GCC clocks need to vote for max uV and the new voltage level defined. Add support for the same by defining new voltage level. Change-Id: Ia7a5693d7177a1cc737091f7fe2aa7ba60ebfbb6 Signed-off-by: Odelu Kukatla --- drivers/clk/msm/clock-a7.c | 1 + drivers/clk/msm/vdd-level-9650.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/msm/clock-a7.c b/drivers/clk/msm/clock-a7.c index 96f52df8f830..1dd67b6daed6 100644 --- a/drivers/clk/msm/clock-a7.c +++ b/drivers/clk/msm/clock-a7.c @@ -221,6 +221,7 @@ static int of_get_fmax_vdd_class(struct platform_device *pdev, struct clk *c, devm_kfree(&pdev->dev, array); vdd->num_levels = prop_len; vdd->cur_level = prop_len; + vdd->use_max_uV = true; c->num_fmax = prop_len; return 0; } diff --git a/drivers/clk/msm/vdd-level-9650.h b/drivers/clk/msm/vdd-level-9650.h index d8f95b062fc2..6d496d4a0240 100644 --- a/drivers/clk/msm/vdd-level-9650.h +++ b/drivers/clk/msm/vdd-level-9650.h @@ -90,7 +90,7 @@ static int vdd_corner[] = { RPM_REGULATOR_LEVEL_LOW_SVS, /* VDD_DIG_LOWER */ RPM_REGULATOR_LEVEL_SVS, /* VDD_DIG_LOW */ RPM_REGULATOR_LEVEL_NOM, /* VDD_DIG_NOMINAL */ - RPM_REGULATOR_LEVEL_TURBO, /* VDD_DIG_HIGH */ + RPM_REGULATOR_LEVEL_TURBO_NO_CPR, /* VDD_DIG_HIGH */ }; #endif From e89b7e7221ec3178e7a5a9dbb98726efde5d19be Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Wed, 13 Sep 2017 18:20:13 +0530 Subject: [PATCH 003/392] ARM: dts: msm: Change the voltage level for cpu clock on MDM9650 For MDM9650, CPU clocks need to vote for max uV so change the voltage corner. Change-Id: Ie8dbf5b2f4ed5a2a0115a7fca85e5255be1223ea Signed-off-by: Odelu Kukatla --- arch/arm/boot/dts/qcom/mdm9650.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/mdm9650.dtsi b/arch/arm/boot/dts/qcom/mdm9650.dtsi index 2d46a23ce20e..4bd26f51d411 100644 --- a/arch/arm/boot/dts/qcom/mdm9650.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9650.dtsi @@ -217,7 +217,7 @@ < 200000000 RPM_SMD_REGULATOR_LEVEL_LOW_SVS>, < 384000000 RPM_SMD_REGULATOR_LEVEL_SVS>, < 787200000 RPM_SMD_REGULATOR_LEVEL_NOM>, - <1286400000 RPM_SMD_REGULATOR_LEVEL_TURBO>; + <1286400000 RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR>; cpu-vdd-supply = <&pmd9650_s5_level_ao>; qcom,a7ssmux-opp-store-vcorner = <&CPU0>; From d5f7dc4222e0cd5c601d72fdc5d6610a09bd5c64 Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Thu, 5 Oct 2017 12:19:32 +0530 Subject: [PATCH 004/392] ARM: dts: msm: Change the voltage level for cpu clock on MDM9650 For MDM9650, CPU clocks need to vote for Turbo level so change the voltage corner. Change-Id: I202c6178cceb378cc7f368fe7b6a1c97f4aafdf1 Signed-off-by: Amit Nischal --- arch/arm/boot/dts/qcom/mdm9650.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/mdm9650.dtsi b/arch/arm/boot/dts/qcom/mdm9650.dtsi index 4bd26f51d411..2d46a23ce20e 100644 --- a/arch/arm/boot/dts/qcom/mdm9650.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9650.dtsi @@ -217,7 +217,7 @@ < 200000000 RPM_SMD_REGULATOR_LEVEL_LOW_SVS>, < 384000000 RPM_SMD_REGULATOR_LEVEL_SVS>, < 787200000 RPM_SMD_REGULATOR_LEVEL_NOM>, - <1286400000 RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR>; + <1286400000 RPM_SMD_REGULATOR_LEVEL_TURBO>; cpu-vdd-supply = <&pmd9650_s5_level_ao>; qcom,a7ssmux-opp-store-vcorner = <&CPU0>; From 2361b8931754567bfb6d4bd9a10368a7d341f78a Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Thu, 5 Oct 2017 11:22:41 +0530 Subject: [PATCH 005/392] clk: msm: clock-gcc-9650: Add support to use Max uV for GCC clocks GCC clocks need to vote for max uV so add support for the same by setting the use_max_uV variable of clk_vdd_class struct to true for MDM9650. Change-Id: I0bdf5f5f700c6cfcc03d67438b020ada4c415f52 Signed-off-by: Amit Nischal --- drivers/clk/msm/clock-gcc-9650.c | 5 +++++ drivers/clk/msm/vdd-level-9650.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/clk/msm/clock-gcc-9650.c b/drivers/clk/msm/clock-gcc-9650.c index e2912ff869b4..e454707952b0 100644 --- a/drivers/clk/msm/clock-gcc-9650.c +++ b/drivers/clk/msm/clock-gcc-9650.c @@ -1734,6 +1734,11 @@ static int msm_gcc_9650_probe(struct platform_device *pdev) if (ret) return ret; + if (of_device_is_compatible(pdev->dev.of_node, "qcom,gcc-9650")) { + vdd_dig.use_max_uV = true; + vdd_dig_ao.use_max_uV = true; + } + for_sdx20 = of_device_is_compatible(pdev->dev.of_node, "qcom,gcc-sdx20"); diff --git a/drivers/clk/msm/vdd-level-9650.h b/drivers/clk/msm/vdd-level-9650.h index 6d496d4a0240..d8f95b062fc2 100644 --- a/drivers/clk/msm/vdd-level-9650.h +++ b/drivers/clk/msm/vdd-level-9650.h @@ -90,7 +90,7 @@ static int vdd_corner[] = { RPM_REGULATOR_LEVEL_LOW_SVS, /* VDD_DIG_LOWER */ RPM_REGULATOR_LEVEL_SVS, /* VDD_DIG_LOW */ RPM_REGULATOR_LEVEL_NOM, /* VDD_DIG_NOMINAL */ - RPM_REGULATOR_LEVEL_TURBO_NO_CPR, /* VDD_DIG_HIGH */ + RPM_REGULATOR_LEVEL_TURBO, /* VDD_DIG_HIGH */ }; #endif From 2f0517c342fb5b3738d0caea3ac44eb97f32d63d Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Mon, 14 Aug 2017 17:09:21 +0530 Subject: [PATCH 006/392] ARM: dts: msm: Update VDD restriction parameters for MDM9650 Update thermal VDD restriction parameters for mdm9650 based on recommendation. Updated parameters are as below VDD restriction trigger threshold 10C VDD restriction clear threshold 15C VDD restriction voltage level value 416 Change-Id: I894445adac4fb035c257bc2b61dbc193181024e6 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm/boot/dts/qcom/mdm9650.dtsi | 10 +++++----- arch/arm/boot/dts/qcom/sdx20.dtsi | 10 ++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/qcom/mdm9650.dtsi b/arch/arm/boot/dts/qcom/mdm9650.dtsi index 2d46a23ce20e..45084064bbfc 100644 --- a/arch/arm/boot/dts/qcom/mdm9650.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9650.dtsi @@ -1058,8 +1058,8 @@ qcom,limit-temp = <60>; qcom,temp-hysteresis = <10>; qcom,freq-step = <2>; - qcom,vdd-restriction-temp = <5>; - qcom,vdd-restriction-temp-hysteresis = <10>; + qcom,vdd-restriction-temp = <10>; + qcom,vdd-restriction-temp-hysteresis = <15>; vdd-dig-supply = <&pmd9650_s5_floor_level>; qcom,disable-cx-phase-ctrl; qcom,disable-gfx-phase-ctrl; @@ -1069,9 +1069,9 @@ qcom,vdd-dig-rstr{ qcom,vdd-rstr-reg = "vdd-dig"; - qcom,levels = ; + qcom,levels = ; qcom,min-level = ; }; }; diff --git a/arch/arm/boot/dts/qcom/sdx20.dtsi b/arch/arm/boot/dts/qcom/sdx20.dtsi index 811eef6f2755..cd475d34720f 100644 --- a/arch/arm/boot/dts/qcom/sdx20.dtsi +++ b/arch/arm/boot/dts/qcom/sdx20.dtsi @@ -138,6 +138,16 @@ /delete-node/ qcom,spm@b009000; /delete-node/ qcom,mpm@601b8; /delete-node/ qcom,lpm-levels; + + qcom,msm-thermal { + qcom,vdd-restriction-temp = <5>; + qcom,vdd-restriction-temp-hysteresis = <10>; + qcom,vdd-dig-rstr{ + qcom,levels = ; + }; + }; }; &clock_gcc { From 93dae1af05a8148315c850766ddf487428858e4c Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Wed, 16 May 2018 22:28:21 +0530 Subject: [PATCH 007/392] dm-req-crypt: Remove discard support as it keep reporting errors Discard support is not required for OTA. Change-Id: I9b202450500663e1040c6d4e77447f5630af0237 Signed-off-by: Ritesh Harjani Signed-off-by: Neeraj Soni --- drivers/md/dm-req-crypt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c index 05b3c3138d75..118c2b130d91 100644 --- a/drivers/md/dm-req-crypt.c +++ b/drivers/md/dm-req-crypt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. @@ -1297,11 +1297,11 @@ static int req_crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) } /* - * If underlying device supports flush/discard, mapped target + * If underlying device supports flush, mapped target * should also allow it */ ti->num_flush_bios = 1; - ti->num_discard_bios = 1; + /* TODO: Discard support */ err = 0; DMINFO("%s: Mapping block_device %s to dm-req-crypt ok!\n", From c38e3f29eebc798a0948021f16387630e0b7512d Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Thu, 16 Mar 2017 17:20:45 -0700 Subject: [PATCH 008/392] diag: Update msg, log and event information Update the diag header with latest log, message and event information to match the list maintained by the peripherals. CRs-Fixed: 2020864 Change-Id: Icbed01bb4f90fb7d72fe7517ee6964d799f1d48e Signed-off-by: Chris Lew Signed-off-by: Manoj Prabhu B --- include/linux/diagchar.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index c3364dce7eea..192bfaaef094 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -144,10 +144,10 @@ the appropriate macros. */ /* This needs to be modified manually now, when we add a new RANGE of SSIDs to the msg_mask_tbl */ #define MSG_MASK_TBL_CNT 26 -#define APPS_EVENT_LAST_ID 0x0B2A +#define APPS_EVENT_LAST_ID 0x0B3F #define MSG_SSID_0 0 -#define MSG_SSID_0_LAST 120 +#define MSG_SSID_0_LAST 121 #define MSG_SSID_1 500 #define MSG_SSID_1_LAST 506 #define MSG_SSID_2 1000 @@ -159,7 +159,7 @@ the appropriate macros. */ #define MSG_SSID_5 4000 #define MSG_SSID_5_LAST 4010 #define MSG_SSID_6 4500 -#define MSG_SSID_6_LAST 4573 +#define MSG_SSID_6_LAST 4583 #define MSG_SSID_7 4600 #define MSG_SSID_7_LAST 4615 #define MSG_SSID_8 5000 @@ -183,7 +183,7 @@ the appropriate macros. */ #define MSG_SSID_17 9000 #define MSG_SSID_17_LAST 9008 #define MSG_SSID_18 9500 -#define MSG_SSID_18_LAST 9510 +#define MSG_SSID_18_LAST 9521 #define MSG_SSID_19 10200 #define MSG_SSID_19_LAST 10210 #define MSG_SSID_20 10251 @@ -340,7 +340,8 @@ static const uint32_t msg_bld_masks_0[] = { MSG_LVL_MED, MSG_LVL_HIGH, MSG_LVL_LOW, - MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL + MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL, + MSG_LVL_HIGH }; static const uint32_t msg_bld_masks_1[] = { @@ -873,7 +874,7 @@ static const uint32_t msg_bld_masks_25[] = { /* LOG CODES */ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 0 */ - 0x1A02, /* EQUIP ID 1 */ + 0x1A11, /* EQUIP ID 1 */ 0x0, /* EQUIP ID 2 */ 0x0, /* EQUIP ID 3 */ 0x4910, /* EQUIP ID 4 */ From 038c3f35d881c18c2abfdd43de2e5df9c790d800 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Mon, 2 Jul 2018 16:31:45 +0530 Subject: [PATCH 009/392] diag: Add new Diag IDs Update to latest diag IDs Change-Id: I57a25f570484f2cd8255275015ca2c70294a78fb Signed-off-by: Sreelakshmi Gownipalli Signed-off-by: Manoj Prabhu B --- include/linux/diagchar.h | 50 ++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index 192bfaaef094..70a1024bc540 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -144,10 +144,10 @@ the appropriate macros. */ /* This needs to be modified manually now, when we add a new RANGE of SSIDs to the msg_mask_tbl */ #define MSG_MASK_TBL_CNT 26 -#define APPS_EVENT_LAST_ID 0x0B3F +#define APPS_EVENT_LAST_ID 0x0C5A #define MSG_SSID_0 0 -#define MSG_SSID_0_LAST 121 +#define MSG_SSID_0_LAST 125 #define MSG_SSID_1 500 #define MSG_SSID_1_LAST 506 #define MSG_SSID_2 1000 @@ -159,11 +159,11 @@ the appropriate macros. */ #define MSG_SSID_5 4000 #define MSG_SSID_5_LAST 4010 #define MSG_SSID_6 4500 -#define MSG_SSID_6_LAST 4583 +#define MSG_SSID_6_LAST 4584 #define MSG_SSID_7 4600 -#define MSG_SSID_7_LAST 4615 +#define MSG_SSID_7_LAST 4616 #define MSG_SSID_8 5000 -#define MSG_SSID_8_LAST 5033 +#define MSG_SSID_8_LAST 5034 #define MSG_SSID_9 5500 #define MSG_SSID_9_LAST 5516 #define MSG_SSID_10 6000 @@ -263,7 +263,7 @@ static const uint32_t msg_bld_masks_0[] = { MSG_MASK_6|MSG_MASK_7|MSG_MASK_8|MSG_MASK_9|MSG_MASK_10, MSG_LVL_MED, MSG_LVL_LOW, - MSG_LVL_LOW, + MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_LOW, MSG_LVL_LOW, @@ -316,7 +316,7 @@ static const uint32_t msg_bld_masks_0[] = { MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL, MSG_LVL_MED, MSG_LVL_HIGH, - MSG_LVL_LOW, + MSG_LVL_MED, MSG_LVL_HIGH, MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL, MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR, @@ -485,6 +485,7 @@ static const uint32_t msg_bld_masks_6[] = { MSG_LVL_LOW, MSG_LVL_LOW, MSG_LVL_LOW, + MSG_LVL_LOW, MSG_LVL_LOW }; @@ -504,7 +505,9 @@ static const uint32_t msg_bld_masks_7[] = { MSG_LVL_LOW, MSG_LVL_LOW, MSG_LVL_LOW, - MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL + MSG_LVL_LOW | MSG_LVL_MED | MSG_LVL_HIGH | MSG_LVL_ERROR | + MSG_LVL_FATAL, + MSG_LVL_LOW }; static const uint32_t msg_bld_masks_8[] = { @@ -524,9 +527,6 @@ static const uint32_t msg_bld_masks_8[] = { MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_MED, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_MED, @@ -541,6 +541,10 @@ static const uint32_t msg_bld_masks_8[] = { MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_HIGH, MSG_LVL_HIGH }; @@ -643,14 +647,14 @@ static const uint32_t msg_bld_masks_10[] = { MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, MSG_LVL_MED }; @@ -796,7 +800,9 @@ static const uint32_t msg_bld_masks_19[] = { }; static const uint32_t msg_bld_masks_20[] = { - MSG_LVL_LOW, + MSG_LVL_LOW | MSG_MASK_5 | MSG_MASK_6 | MSG_MASK_7 | + MSG_MASK_8 | MSG_MASK_9 | MSG_MASK_10 | MSG_MASK_11 | + MSG_MASK_12, MSG_LVL_LOW, MSG_LVL_LOW, MSG_LVL_LOW, @@ -874,7 +880,7 @@ static const uint32_t msg_bld_masks_25[] = { /* LOG CODES */ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 0 */ - 0x1A11, /* EQUIP ID 1 */ + 0x1C68, /* EQUIP ID 1 */ 0x0, /* EQUIP ID 2 */ 0x0, /* EQUIP ID 3 */ 0x4910, /* EQUIP ID 4 */ @@ -884,7 +890,7 @@ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 8 */ 0x0, /* EQUIP ID 9 */ 0xA38A, /* EQUIP ID 10 */ - 0xB201, /* EQUIP ID 11 */ + 0xB9FF, /* EQUIP ID 11 */ 0x0, /* EQUIP ID 12 */ 0xD1FF, /* EQUIP ID 13 */ 0x0, /* EQUIP ID 14 */ From b70052fd9aefd94a469fda18187090759a0ea59d Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Thu, 17 May 2018 12:08:51 +0530 Subject: [PATCH 010/392] diag: Add new log codes to diag mask The patch adds new requested log codes to diag mask. Change-Id: I4124e55077ae63b9c0c349feed409851108261d3 Signed-off-by: Manoj Prabhu B --- include/linux/diagchar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index 70a1024bc540..332cb1b38413 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -880,7 +880,7 @@ static const uint32_t msg_bld_masks_25[] = { /* LOG CODES */ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 0 */ - 0x1C68, /* EQUIP ID 1 */ + 0x1C6A, /* EQUIP ID 1 */ 0x0, /* EQUIP ID 2 */ 0x0, /* EQUIP ID 3 */ 0x4910, /* EQUIP ID 4 */ From b21ec443e4335c563aababd4905f3684565bb5cc Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Wed, 16 May 2018 22:25:41 +0530 Subject: [PATCH 011/392] dm-req-crypt: Add support for immutable bio_vec Make fixes according to immutable biovec for proper parsing of bio and allocated page association. Change-Id: I2d0dc00556772a374ed9c6132082e1af3ab5d6b5 Signed-off-by: Neeraj Soni --- drivers/md/dm-req-crypt.c | 86 +++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c index 118c2b130d91..0534772696a0 100644 --- a/drivers/md/dm-req-crypt.c +++ b/drivers/md/dm-req-crypt.c @@ -457,22 +457,22 @@ static void req_cryptd_crypt_write_convert(struct req_dm_crypt_io *io) struct bio *bio_src = NULL; unsigned int total_sg_len_req_in = 0, total_sg_len_req_out = 0, total_bytes_in_req = 0, error = DM_MAPIO_REMAPPED, rc = 0; - struct req_iterator iter; - struct req_iterator iter1; struct ablkcipher_request *req = NULL; struct req_crypt_result result; - struct bio_vec bvec; struct scatterlist *req_sg_in = NULL; struct scatterlist *req_sg_out = NULL; int copy_bio_sector_to_req = 0; gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM; struct page *page = NULL; u8 IV[AES_XTS_IV_LEN]; - int remaining_size = 0, err = 0; + int size = 0, err = 0; struct crypto_engine_entry engine; unsigned int engine_list_total = 0; struct crypto_engine_entry *curr_engine_list = NULL; unsigned int *engine_cursor = NULL; + unsigned int i; + struct bio_vec *_bvec; + struct bio *_bio; if (io) { @@ -582,27 +582,31 @@ static void req_cryptd_crypt_write_convert(struct req_dm_crypt_io *io) goto ablkcipher_req_alloc_failure; } - rq_for_each_segment(bvec, clone, iter) { - if (bvec.bv_len > remaining_size) { - page = NULL; - while (page == NULL) { - page = mempool_alloc(req_page_pool, gfp_mask); - if (!page) { - DMERR("%s Crypt page alloc failed", + __rq_for_each_bio(_bio, clone) { + bio_for_each_segment_all(_bvec, _bio, i) { + if (_bvec->bv_len > size) { + page = NULL; + while (page == NULL) { + page = mempool_alloc(req_page_pool, + gfp_mask); + if (!page) { + DMERR("%s Page alloc failed", __func__); - congestion_wait(BLK_RW_ASYNC, HZ/100); + congestion_wait(BLK_RW_ASYNC, + HZ/100); + } } - } - bvec.bv_page = page; - bvec.bv_offset = 0; - remaining_size = PAGE_SIZE - bvec.bv_len; - if (remaining_size < 0) - BUG(); - } else { - bvec.bv_page = page; - bvec.bv_offset = PAGE_SIZE - remaining_size; - remaining_size = remaining_size - bvec.bv_len; + _bvec->bv_page = page; + _bvec->bv_offset = 0; + size = PAGE_SIZE - _bvec->bv_len; + if (size < 0) + BUG(); + } else { + _bvec->bv_page = page; + _bvec->bv_offset = PAGE_SIZE - size; + size = size - _bvec->bv_len; + } } } @@ -664,12 +668,16 @@ static void req_cryptd_crypt_write_convert(struct req_dm_crypt_io *io) ablkcipher_request_free(req); if (error == DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC) { - rq_for_each_segment(bvec, clone, iter1) { - if (bvec.bv_offset == 0) { - mempool_free(bvec.bv_page, req_page_pool); - bvec.bv_page = NULL; - } else - bvec.bv_page = NULL; + __rq_for_each_bio(_bio, clone) { + bio_for_each_segment_all(_bvec, _bio, i) { + if (_bvec->bv_offset == 0) { + mempool_free(_bvec->bv_page, + req_page_pool); + _bvec->bv_page = NULL; + } else { + _bvec->bv_page = NULL; + } + } } } @@ -866,8 +874,9 @@ static int req_crypt_endio(struct dm_target *ti, struct request *clone, int error, union map_info *map_context) { int err = 0; - struct req_iterator iter1; - struct bio_vec bvec; + struct bio_vec *_bvec; + struct bio *_bio; + unsigned int i; struct req_dm_crypt_io *req_io = map_context->ptr; /* If it is for ICE, free up req_io and return */ @@ -878,12 +887,17 @@ static int req_crypt_endio(struct dm_target *ti, struct request *clone, } if (rq_data_dir(clone) == WRITE) { - rq_for_each_segment(bvec, clone, iter1) { - if (req_io->should_encrypt && bvec.bv_offset == 0) { - mempool_free(bvec.bv_page, req_page_pool); - bvec.bv_page = NULL; - } else - bvec.bv_page = NULL; + __rq_for_each_bio(_bio, clone) { + bio_for_each_segment_all(_bvec, _bio, i) { + if (req_io->should_encrypt && + _bvec->bv_offset == 0) { + mempool_free(_bvec->bv_page, + req_page_pool); + _bvec->bv_page = NULL; + } else { + _bvec->bv_page = NULL; + } + } } mempool_free(req_io, req_io_pool); goto submit_request; From 4348bcd4c825f775f53469f3d9ed0e30a24e501f Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Wed, 16 May 2018 22:14:14 +0530 Subject: [PATCH 012/392] Revert "dm: remove nr_iovecs parameter from alloc_tio()" This reverts commit 997782735c0f1e2e069337129fe0d5738d83d19b. This is required for request based device mapper to function properly. Change-Id: I0c12cca56b82c0ecb133f6b5e5fa70d940e9a284 Signed-off-by: Ritesh Harjani Signed-off-by: Neeraj Soni --- drivers/md/dm.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index adc2783761aa..52513032e47a 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1427,13 +1427,13 @@ static void clone_bio(struct dm_target_io *tio, struct bio *bio, } static struct dm_target_io *alloc_tio(struct clone_info *ci, - struct dm_target *ti, + struct dm_target *ti, int nr_iovecs, unsigned target_bio_nr) { struct dm_target_io *tio; struct bio *clone; - clone = bio_alloc_bioset(GFP_NOIO, 0, ci->md->bs); + clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, ci->md->bs); tio = container_of(clone, struct dm_target_io, clone); tio->io = ci->io; @@ -1447,12 +1447,18 @@ static void __clone_and_map_simple_bio(struct clone_info *ci, struct dm_target *ti, unsigned target_bio_nr, unsigned *len) { - struct dm_target_io *tio = alloc_tio(ci, ti, target_bio_nr); + struct dm_target_io *tio = alloc_tio(ci, ti, ci->bio->bi_max_vecs, + target_bio_nr); struct bio *clone = &tio->clone; tio->len_ptr = len; - __bio_clone_fast(clone, ci->bio); + /* + * Discard requests require the bio's inline iovecs be initialized. + * ci->bio->bi_max_vecs is BIO_INLINE_VECS anyway, for both flush + * and discard, so no need for concern about wasted bvec allocations. + */ + __bio_clone_fast(clone, ci->bio); if (len) bio_setup_sector(clone, ci->sector, *len); @@ -1495,7 +1501,7 @@ static void __clone_and_map_data_bio(struct clone_info *ci, struct dm_target *ti num_target_bios = ti->num_write_bios(ti, bio); for (target_bio_nr = 0; target_bio_nr < num_target_bios; target_bio_nr++) { - tio = alloc_tio(ci, ti, target_bio_nr); + tio = alloc_tio(ci, ti, 0, target_bio_nr); tio->len_ptr = len; clone_bio(tio, bio, sector, *len); __map_bio(tio); From 86bc100a1830e2f5d11cb0e8a5877e7635004946 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Wed, 16 May 2018 22:14:27 +0530 Subject: [PATCH 013/392] Revert "block: use bio_clone_fast() in blk_rq_prep_clone()" This reverts commit 11dfce509eaa35e8fc81cb50d0910c0e235fd7e2. Change-Id: I20309b840f7db91b0d6df1073e60a099fea710b2 Signed-off-by: Ritesh Harjani Signed-off-by: Neeraj Soni --- block/blk-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk-core.c b/block/blk-core.c index 950eea0eee2e..ed38f2d14976 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2966,7 +2966,7 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src, blk_rq_init(NULL, rq); __rq_for_each_bio(bio_src, rq_src) { - bio = bio_clone_fast(bio_src, gfp_mask, bs); + bio = bio_clone_bioset(bio_src, gfp_mask, bs); if (!bio) goto free_and_out; From ad6c99bc3a1a1fd5bf746b60ced834c235a9f24d Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Tue, 22 May 2018 15:49:29 +0530 Subject: [PATCH 014/392] md:dm: Fix Key size for GPCE Key size should be same for OTA to work properly. Change-Id: I9b3bdb7c07aeb847af447cfd1a8d2df038f4821b Signed-off-by: Neeraj Soni --- drivers/md/dm-req-crypt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c index 0534772696a0..196952d49b40 100644 --- a/drivers/md/dm-req-crypt.c +++ b/drivers/md/dm-req-crypt.c @@ -42,7 +42,7 @@ #define MAX_ENCRYPTION_BUFFERS 1 #define MIN_IOS 256 #define MIN_POOL_PAGES 32 -#define KEY_SIZE_XTS 32 +#define KEY_SIZE_XTS 64 #define AES_XTS_IV_LEN 16 #define MAX_MSM_ICE_KEY_LUT_SIZE 32 #define SECTOR_SIZE 512 From e156539cb4a36ecaf3ebaa8765f956bf1f89966b Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Mon, 2 Jul 2018 19:20:53 +0530 Subject: [PATCH 015/392] msm: mhi_dev: Log BHI_IMGTXDB register Log BHI_IMGTXDB register upon receiving M0/M3 from Host. Change-Id: I53943fae1f27fa61c56a688156a734d8bc308248 Signed-off-by: Rama Krishna Phani A --- drivers/platform/msm/mhi_dev/mhi.c | 5 +++++ drivers/platform/msm/mhi_dev/mhi_hwio.h | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index aa895618d90a..056c999bcfbf 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -1480,6 +1480,7 @@ static void mhi_dev_scheduler(struct work_struct *work) enum mhi_dev_state state; enum mhi_dev_event event = 0; bool mhi_reset = false; + uint32_t bhi_imgtxdb = 0; mutex_lock(&mhi_ctx->mhi_lock); /* Check for interrupts */ @@ -1517,6 +1518,10 @@ static void mhi_dev_scheduler(struct work_struct *work) pr_err("error sending SM event\n"); goto fail; } + + rc = mhi_dev_mmio_read(mhi, BHI_IMGTXDB, &bhi_imgtxdb); + mhi_log(MHI_MSG_VERBOSE, + "BHI_IMGTXDB = 0x%x\n", bhi_imgtxdb); } if (int_value & MHI_MMIO_CTRL_CRDB_STATUS_MSK) { diff --git a/drivers/platform/msm/mhi_dev/mhi_hwio.h b/drivers/platform/msm/mhi_dev/mhi_hwio.h index 40e1a91a980a..db46f2795c93 100644 --- a/drivers/platform/msm/mhi_dev/mhi_hwio.h +++ b/drivers/platform/msm/mhi_dev/mhi_hwio.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -192,4 +192,6 @@ #define BHI_EXECENV_MASK 0xFFFFFFFF #define BHI_EXECENV_SHIFT 0 +#define BHI_IMGTXDB (0x218) + #endif From 293c3942ba02e750c87c0c7b211bfe085fb5728f Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 17 Apr 2018 17:53:40 +0530 Subject: [PATCH 016/392] msm: adsprpc: destroy mutex before file free Destroy mutex before file free, to avoid use after free of mutex. Change-Id: I4ff73dc17b15043eacbb299219a379bfd1a8efa6 Acked-by: Himateja Reddy Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 37d1c3836d0a..69de8258d10f 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1843,8 +1843,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl) spin_unlock(&fl->apps->hlock); if (!fl->sctx) { - kfree(fl); - return 0; + goto bail; } (void)fastrpc_release_current_dsp_process(fl); @@ -1856,6 +1855,9 @@ static int fastrpc_file_free(struct fastrpc_file *fl) if (fl->ssrcount == fl->apps->channel[cid].ssrcount) kref_put_mutex(&fl->apps->channel[cid].kref, fastrpc_channel_close, &fl->apps->smd_mutex); + +bail: + mutex_destroy(&fl->map_mutex); kfree(fl); return 0; } @@ -2009,7 +2011,6 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) } me->pending_free++; mutex_unlock(&me->flfree_mutex); - mutex_destroy(&fl->map_mutex); file->private_data = NULL; } bail: From 6c67d32c3e91acba748d80aa66f8ef09044f0d7a Mon Sep 17 00:00:00 2001 From: Ramprasad Katkam Date: Mon, 2 Jul 2018 14:54:42 +0530 Subject: [PATCH 017/392] ASoC: msm: qdsp6v2: Add mutex protection for rtac cal apis Add mutex lock protection to synchronize rtac calibration set and get api calls. Change-Id: Ieb2d01642ecefff6405bb59554157c304b4b651d Signed-off-by: Ramprasad Katkam --- sound/soc/msm/qdsp6v2/rtac.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c index 9b5e72f94d1b..11c46335993e 100644 --- a/sound/soc/msm/qdsp6v2/rtac.c +++ b/sound/soc/msm/qdsp6v2/rtac.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -127,6 +127,11 @@ struct mutex rtac_voice_mutex; struct mutex rtac_voice_apr_mutex; struct mutex rtac_afe_apr_mutex; +static struct mutex rtac_asm_cal_mutex; +static struct mutex rtac_adm_cal_mutex; +static struct mutex rtac_afe_cal_mutex; +static struct mutex rtac_voice_cal_mutex; + int rtac_clear_mapping(uint32_t cal_type) { int result = 0; @@ -1693,42 +1698,62 @@ static long rtac_ioctl_shared(struct file *f, } case AUDIO_GET_RTAC_ADM_CAL: + mutex_lock(&rtac_adm_cal_mutex); result = send_adm_apr((void *)arg, ADM_CMD_GET_PP_PARAMS_V5); + mutex_unlock(&rtac_adm_cal_mutex); break; case AUDIO_SET_RTAC_ADM_CAL: + mutex_lock(&rtac_adm_cal_mutex); result = send_adm_apr((void *)arg, ADM_CMD_SET_PP_PARAMS_V5); + mutex_unlock(&rtac_adm_cal_mutex); break; case AUDIO_GET_RTAC_ASM_CAL: + mutex_lock(&rtac_asm_cal_mutex); result = send_rtac_asm_apr((void *)arg, ASM_STREAM_CMD_GET_PP_PARAMS_V2); + mutex_unlock(&rtac_asm_cal_mutex); break; case AUDIO_SET_RTAC_ASM_CAL: + mutex_lock(&rtac_asm_cal_mutex); result = send_rtac_asm_apr((void *)arg, ASM_STREAM_CMD_SET_PP_PARAMS_V2); + mutex_unlock(&rtac_asm_cal_mutex); break; case AUDIO_GET_RTAC_CVS_CAL: + mutex_lock(&rtac_voice_cal_mutex); result = send_voice_apr(RTAC_CVS, (void *)arg, VOICE_CMD_GET_PARAM); + mutex_unlock(&rtac_voice_cal_mutex); break; case AUDIO_SET_RTAC_CVS_CAL: + mutex_lock(&rtac_voice_cal_mutex); result = send_voice_apr(RTAC_CVS, (void *)arg, VOICE_CMD_SET_PARAM); + mutex_unlock(&rtac_voice_cal_mutex); break; case AUDIO_GET_RTAC_CVP_CAL: + mutex_lock(&rtac_voice_cal_mutex); result = send_voice_apr(RTAC_CVP, (void *)arg, VOICE_CMD_GET_PARAM); + mutex_unlock(&rtac_voice_cal_mutex); break; case AUDIO_SET_RTAC_CVP_CAL: + mutex_lock(&rtac_voice_cal_mutex); result = send_voice_apr(RTAC_CVP, (void *)arg, VOICE_CMD_SET_PARAM); + mutex_unlock(&rtac_voice_cal_mutex); break; case AUDIO_GET_RTAC_AFE_CAL: + mutex_lock(&rtac_afe_cal_mutex); result = send_rtac_afe_apr((void *)arg, AFE_PORT_CMD_GET_PARAM_V2); + mutex_unlock(&rtac_afe_cal_mutex); break; case AUDIO_SET_RTAC_AFE_CAL: + mutex_lock(&rtac_afe_cal_mutex); result = send_rtac_afe_apr((void *)arg, AFE_PORT_CMD_SET_PARAM_V2); + mutex_unlock(&rtac_afe_cal_mutex); break; default: pr_err("%s: Invalid IOCTL, command = %d!\n", @@ -1860,6 +1885,7 @@ static int __init rtac_init(void) init_waitqueue_head(&rtac_adm_apr_data.cmd_wait); mutex_init(&rtac_adm_mutex); mutex_init(&rtac_adm_apr_mutex); + mutex_init(&rtac_adm_cal_mutex); rtac_adm_buffer = kzalloc( rtac_cal[ADM_RTAC_CAL].map_data.map_size, GFP_KERNEL); @@ -1876,6 +1902,7 @@ static int __init rtac_init(void) init_waitqueue_head(&rtac_asm_apr_data[i].cmd_wait); } mutex_init(&rtac_asm_apr_mutex); + mutex_init(&rtac_asm_cal_mutex); rtac_asm_buffer = kzalloc( rtac_cal[ASM_RTAC_CAL].map_data.map_size, GFP_KERNEL); @@ -1891,6 +1918,7 @@ static int __init rtac_init(void) atomic_set(&rtac_afe_apr_data.cmd_state, 0); init_waitqueue_head(&rtac_afe_apr_data.cmd_wait); mutex_init(&rtac_afe_apr_mutex); + mutex_init(&rtac_afe_cal_mutex); rtac_afe_buffer = kzalloc( rtac_cal[AFE_RTAC_CAL].map_data.map_size, GFP_KERNEL); @@ -1911,6 +1939,7 @@ static int __init rtac_init(void) } mutex_init(&rtac_voice_mutex); mutex_init(&rtac_voice_apr_mutex); + mutex_init(&rtac_voice_cal_mutex); rtac_voice_buffer = kzalloc( rtac_cal[VOICE_RTAC_CAL].map_data.map_size, GFP_KERNEL); From 283d837c16bbeeb4bee8610ef5816db2621f0fd5 Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Wed, 13 Jun 2018 20:59:29 +0530 Subject: [PATCH 018/392] ion: invalidate the pool pointers after free ion_system_heap_destroy_pools frees the pool, but does not invalidate the pointer. This can result in a double free if ion_system_heap_create_pools fails, and then causes ion_system_heap_create to call into ion_system_heap_destroy_pools again from the error path. This can happen in ion_system_heap_create when one of the secure pool creation fails. Change-Id: Ic73ca78722aa5a575cc4dd7c1caa560b518094f2 Signed-off-by: Vinayak Menon --- drivers/staging/android/ion/ion_system_heap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 062de5ae1738..735f5f24a5f0 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -2,7 +2,7 @@ * drivers/staging/android/ion/ion_system_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -619,8 +619,10 @@ static void ion_system_heap_destroy_pools(struct ion_page_pool **pools) { int i; for (i = 0; i < num_orders; i++) - if (pools[i]) + if (pools[i]) { ion_page_pool_destroy(pools[i]); + pools[i] = NULL; + } } /** From ccecc02abe96f9adb4b5584e10e68fc2df9c0fe0 Mon Sep 17 00:00:00 2001 From: Sanjay Dwivedi Date: Fri, 1 Jun 2018 12:34:43 +0530 Subject: [PATCH 019/392] defconfig: mdm9650: Boot KPI improvement Removing configs which are not supported or not required. Change-Id: I1347bf1c6e898c1dc22ea3d97ade341de72dde2f Signed-off-by: Sanjay Dwivedi --- arch/arm/configs/mdm-perf_defconfig | 26 ++------------------------ arch/arm/configs/mdm_defconfig | 26 ++------------------------ 2 files changed, 4 insertions(+), 48 deletions(-) diff --git a/arch/arm/configs/mdm-perf_defconfig b/arch/arm/configs/mdm-perf_defconfig index 9b207032aeee..09a3f1e14f6d 100644 --- a/arch/arm/configs/mdm-perf_defconfig +++ b/arch/arm/configs/mdm-perf_defconfig @@ -27,7 +27,6 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_MSM=y -CONFIG_ARCH_MDM9640=y CONFIG_ARCH_MDM9650=y CONFIG_PCI_MSM=y CONFIG_PREEMPT=y @@ -205,7 +204,7 @@ CONFIG_TUN=y # CONFIG_NET_VENDOR_CIRRUS is not set # CONFIG_NET_VENDOR_FARADAY is not set # CONFIG_NET_VENDOR_INTEL is not set -CONFIG_KS8851=y +# CONFIG_NET_VENDOR_MICREL is not set # CONFIG_NET_VENDOR_MICROCHIP is not set CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y @@ -238,7 +237,6 @@ CONFIG_INPUT_EVDEV=y CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m -CONFIG_SERIO_LIBPS2=y # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_HSL=y @@ -282,12 +280,7 @@ CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_SOC_MDM9650=y -CONFIG_UHID=y -CONFIG_HID_APPLE=y -CONFIG_HID_ELECOM=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MULTITOUCH=y +# CONFIG_HID_GENERIC is not set CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y @@ -295,19 +288,6 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y CONFIG_USB_EHCI_MSM_HSIC=y CONFIG_USB_ACM=y -CONFIG_USB_STORAGE=y -CONFIG_USB_STORAGE_DEBUG=y -CONFIG_USB_STORAGE_DATAFAB=y -CONFIG_USB_STORAGE_FREECOM=y -CONFIG_USB_STORAGE_ISD200=y -CONFIG_USB_STORAGE_USBAT=y -CONFIG_USB_STORAGE_SDDR09=y -CONFIG_USB_STORAGE_SDDR55=y -CONFIG_USB_STORAGE_JUMPSHOT=y -CONFIG_USB_STORAGE_ALAUDA=y -CONFIG_USB_STORAGE_ONETOUCH=y -CONFIG_USB_STORAGE_KARMA=y -CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_USB_DWC3=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y @@ -399,8 +379,6 @@ CONFIG_DEVFREQ_SPDM=y CONFIG_IIO=y CONFIG_IIO_BUFFER=y CONFIG_IIO_BUFFER_CB=y -CONFIG_IIO_ST_ACCEL_3AXIS=y -CONFIG_IIO_ST_GYRO_3AXIS=y CONFIG_SENSORS_BMI160_IIO=y CONFIG_SENSORS_BMI160_IIO_RING=y CONFIG_ENABLE_ACC_GYRO_BUFFERING=y diff --git a/arch/arm/configs/mdm_defconfig b/arch/arm/configs/mdm_defconfig index bffd18813078..031eceff80ed 100644 --- a/arch/arm/configs/mdm_defconfig +++ b/arch/arm/configs/mdm_defconfig @@ -205,7 +205,7 @@ CONFIG_TUN=y # CONFIG_NET_VENDOR_CIRRUS is not set # CONFIG_NET_VENDOR_FARADAY is not set # CONFIG_NET_VENDOR_INTEL is not set -CONFIG_KS8851=y +# CONFIG_NET_VENDOR_MICREL is not set # CONFIG_NET_VENDOR_MICROCHIP is not set CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y @@ -238,7 +238,6 @@ CONFIG_INPUT_EVDEV=y CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m -CONFIG_SERIO_LIBPS2=y # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_HSL=y @@ -259,7 +258,6 @@ CONFIG_SPI_SPIDEV=m CONFIG_PPS_CLIENT_GPIO=y CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_MDM9607=y -CONFIG_PINCTRL_MDM9640=y CONFIG_PINCTRL_MDM9650=y CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y @@ -289,12 +287,7 @@ CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_SOC_MDM9650=y -CONFIG_UHID=y -CONFIG_HID_APPLE=y -CONFIG_HID_ELECOM=y -CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MULTITOUCH=y +# CONFIG_HID_GENERIC is not set CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y @@ -302,19 +295,6 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y CONFIG_USB_EHCI_MSM_HSIC=y CONFIG_USB_ACM=y -CONFIG_USB_STORAGE=y -CONFIG_USB_STORAGE_DEBUG=y -CONFIG_USB_STORAGE_DATAFAB=y -CONFIG_USB_STORAGE_FREECOM=y -CONFIG_USB_STORAGE_ISD200=y -CONFIG_USB_STORAGE_USBAT=y -CONFIG_USB_STORAGE_SDDR09=y -CONFIG_USB_STORAGE_SDDR55=y -CONFIG_USB_STORAGE_JUMPSHOT=y -CONFIG_USB_STORAGE_ALAUDA=y -CONFIG_USB_STORAGE_ONETOUCH=y -CONFIG_USB_STORAGE_KARMA=y -CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_USB_DWC3=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y @@ -411,8 +391,6 @@ CONFIG_DEVFREQ_SPDM=y CONFIG_IIO=y CONFIG_IIO_BUFFER=y CONFIG_IIO_BUFFER_CB=y -CONFIG_IIO_ST_ACCEL_3AXIS=y -CONFIG_IIO_ST_GYRO_3AXIS=y CONFIG_SENSORS_BMI160_IIO=y CONFIG_SENSORS_BMI160_IIO_RING=y CONFIG_ENABLE_ACC_GYRO_BUFFERING=y From c0c2707fd5840c08b0e0b79465bb7b0ab4a65c8d Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Wed, 30 Aug 2017 18:55:59 -0700 Subject: [PATCH 020/392] msm: gsi: gsi_ctx pointer dereference fix Check if gsi_ctx pointer is null before dereferencing it. Change-Id: Icbdd100c00e4d04183af55ef41570414afbdb6c2 CRs-Fixed: 2102065 Signed-off-by: Michael Adisumarta --- drivers/platform/msm/gsi/gsi.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 60a610199836..43d99b9c30d9 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -1099,13 +1099,14 @@ int gsi_alloc_evt_ring(struct gsi_evt_ring_props *props, unsigned long dev_hdl, uint32_t val; struct gsi_evt_ctx *ctx; int res; - int ee = gsi_ctx->per.ee; + int ee; unsigned long flags; if (!gsi_ctx) { pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); return -GSI_STATUS_NODEV; } + ee = gsi_ctx->per.ee; if (!props || !evt_ring_hdl || dev_hdl != (uintptr_t)gsi_ctx) { GSIERR("bad params props=%p dev_hdl=0x%lx evt_ring_hdl=%p\n", @@ -1637,7 +1638,7 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, struct gsi_chan_ctx *ctx; uint32_t val; int res; - int ee = gsi_ctx->per.ee; + int ee; enum gsi_ch_cmd_opcode op = GSI_CH_ALLOCATE; uint8_t erindex; void **user_data; @@ -1646,6 +1647,7 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); return -GSI_STATUS_NODEV; } + ee = gsi_ctx->per.ee; if (!props || !chan_hdl || dev_hdl != (uintptr_t)gsi_ctx) { GSIERR("bad params props=%p dev_hdl=0x%lx chan_hdl=%p\n", @@ -2287,12 +2289,13 @@ int gsi_query_channel_info(unsigned long chan_hdl, unsigned long flags; uint64_t rp; uint64_t wp; - int ee = gsi_ctx->per.ee; + int ee; if (!gsi_ctx) { pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); return -GSI_STATUS_NODEV; } + ee = gsi_ctx->per.ee; if (chan_hdl >= gsi_ctx->max_ch || !info) { GSIERR("bad params chan_hdl=%lu info=%p\n", chan_hdl, info); @@ -2357,12 +2360,13 @@ int gsi_is_channel_empty(unsigned long chan_hdl, bool *is_empty) unsigned long flags; uint64_t rp; uint64_t wp; - int ee = gsi_ctx->per.ee; + int ee; if (!gsi_ctx) { pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); return -GSI_STATUS_NODEV; } + ee = gsi_ctx->per.ee; if (chan_hdl >= gsi_ctx->max_ch || !is_empty) { GSIERR("bad params chan_hdl=%lu is_empty=%p\n", @@ -2546,13 +2550,14 @@ int gsi_poll_channel(unsigned long chan_hdl, { struct gsi_chan_ctx *ctx; uint64_t rp; - int ee = gsi_ctx->per.ee; + int ee; unsigned long flags; if (!gsi_ctx) { pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); return -GSI_STATUS_NODEV; } + ee = gsi_ctx->per.ee; if (chan_hdl >= gsi_ctx->max_ch || !notify) { GSIERR("bad params chan_hdl=%lu notify=%p\n", chan_hdl, notify); From b19087e5b9fc7ad9c9afe0f759a6358bc0533883 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 3 Jul 2018 11:31:07 +0530 Subject: [PATCH 021/392] sched: qhmp: Fix compilation for IRQ_TIME_ACCOUNTING When IRQ_TIME_ACCOUNTING feature is enabled, compiler gives an undefined reference error for sched_account_irqstart function. Since cycle counter based accounting is not needed for any targets that are using QHMP scheduler, provide a nop definition for this function. Change-Id: Id34e26c4e8d38db953e5d8e1f527e20a1772fe3a Signed-off-by: Pavankumar Kondeti --- kernel/sched/qhmp_sched.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/sched/qhmp_sched.h b/kernel/sched/qhmp_sched.h index 3a3a048b01e5..5dca2d9ec0f5 100644 --- a/kernel/sched/qhmp_sched.h +++ b/kernel/sched/qhmp_sched.h @@ -1081,6 +1081,12 @@ static inline int sched_cpu_high_irqload(int cpu) { return 0; } #endif /* CONFIG_SCHED_HMP */ +/* cycle counter based accounting is not available in QHMP. */ +static inline void sched_account_irqstart(int cpu, struct task_struct *curr, + u64 wallclock) +{ +} + #ifdef CONFIG_SCHED_FREQ_INPUT extern void check_for_freq_change(struct rq *rq); From 3f9bd5d111ddd97f3b3d0a52e4619144c8e84be7 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Wed, 27 Jun 2018 16:05:57 +0530 Subject: [PATCH 022/392] diag: Update mask buffer after reallocation Currently, reallocated mask update buffers are not updated if the received mask range is more than the mask update buffer length. Update the reallocated buffer address before writing the mask to peripherals. CRs-Fixed: 2266693 Change-Id: I6b506ce68e17b7da61926b0f9543157812a8c555 Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diag_masks.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index dd20aec9983e..4b24df4b6e4c 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -168,10 +168,11 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id) } mask_info->update_buf = temp; mask_info->update_buf_len = header_len + mask_size; + buf = temp; } memcpy(buf, &ctrl_pkt, header_len); - if (mask_size > 0) + if (mask_size > 0 && mask_size <= LOG_MASK_SIZE) memcpy(buf + header_len, mask->ptr, mask_size); mutex_unlock(&mask->lock); @@ -255,9 +256,16 @@ static void diag_send_event_mask_update(uint8_t peripheral) } else { mask_info->update_buf = temp; mask_info->update_buf_len = temp_len; + buf = temp; } } - memcpy(buf + sizeof(header), mask_info->ptr, num_bytes); + if (num_bytes > 0 && num_bytes < mask_info->mask_len) + memcpy(buf + sizeof(header), mask_info->ptr, num_bytes); + else { + pr_err("diag: num_bytes(%d) is not satisfying length condition\n", + num_bytes); + goto err; + } write_len += num_bytes; break; default: @@ -360,6 +368,7 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) } else { mask_info->update_buf = temp; mask_info->update_buf_len = temp_len; + buf = temp; pr_debug("diag: In %s, successfully reallocated msg_mask update buffer to len: %d\n", __func__, mask_info->update_buf_len); } From 2abce88c3750e073da48e59f546fee565838c6f2 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 28 Nov 2017 18:01:38 -0800 Subject: [PATCH 023/392] crypto: hmac - require that the underlying hash algorithm is unkeyed Because the HMAC template didn't check that its underlying hash algorithm is unkeyed, trying to use "hmac(hmac(sha3-512-generic))" through AF_ALG or through KEYCTL_DH_COMPUTE resulted in the inner HMAC being used without having been keyed, resulting in sha3_update() being called without sha3_init(), causing a stack buffer overflow. This is a very old bug, but it seems to have only started causing real problems when SHA-3 support was added (requires CONFIG_CRYPTO_SHA3) because the innermost hash's state is ->import()ed from a zeroed buffer, and it just so happens that other hash algorithms are fine with that, but SHA-3 is not. However, there could be arch or hardware-dependent hash algorithms also affected; I couldn't test everything. Fix the bug by introducing a function crypto_shash_alg_has_setkey() which tests whether a shash algorithm is keyed. Then update the HMAC template to require that its underlying hash algorithm is unkeyed. Here is a reproducer: #include #include int main() { int algfd; struct sockaddr_alg addr = { .salg_type = "hash", .salg_name = "hmac(hmac(sha3-512-generic))", }; char key[4096] = { 0 }; algfd = socket(AF_ALG, SOCK_SEQPACKET, 0); bind(algfd, (const struct sockaddr *)&addr, sizeof(addr)); setsockopt(algfd, SOL_ALG, ALG_SET_KEY, key, sizeof(key)); } Here was the KASAN report from syzbot: BUG: KASAN: stack-out-of-bounds in memcpy include/linux/string.h:341 [inline] BUG: KASAN: stack-out-of-bounds in sha3_update+0xdf/0x2e0 crypto/sha3_generic.c:161 Write of size 4096 at addr ffff8801cca07c40 by task syzkaller076574/3044 CPU: 1 PID: 3044 Comm: syzkaller076574 Not tainted 4.14.0-mm1+ #25 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x257 lib/dump_stack.c:53 print_address_description+0x73/0x250 mm/kasan/report.c:252 kasan_report_error mm/kasan/report.c:351 [inline] kasan_report+0x25b/0x340 mm/kasan/report.c:409 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x137/0x190 mm/kasan/kasan.c:267 memcpy+0x37/0x50 mm/kasan/kasan.c:303 memcpy include/linux/string.h:341 [inline] sha3_update+0xdf/0x2e0 crypto/sha3_generic.c:161 crypto_shash_update+0xcb/0x220 crypto/shash.c:109 shash_finup_unaligned+0x2a/0x60 crypto/shash.c:151 crypto_shash_finup+0xc4/0x120 crypto/shash.c:165 hmac_finup+0x182/0x330 crypto/hmac.c:152 crypto_shash_finup+0xc4/0x120 crypto/shash.c:165 shash_digest_unaligned+0x9e/0xd0 crypto/shash.c:172 crypto_shash_digest+0xc4/0x120 crypto/shash.c:186 hmac_setkey+0x36a/0x690 crypto/hmac.c:66 crypto_shash_setkey+0xad/0x190 crypto/shash.c:64 shash_async_setkey+0x47/0x60 crypto/shash.c:207 crypto_ahash_setkey+0xaf/0x180 crypto/ahash.c:200 hash_setkey+0x40/0x90 crypto/algif_hash.c:446 alg_setkey crypto/af_alg.c:221 [inline] alg_setsockopt+0x2a1/0x350 crypto/af_alg.c:254 SYSC_setsockopt net/socket.c:1851 [inline] SyS_setsockopt+0x189/0x360 net/socket.c:1830 entry_SYSCALL_64_fastpath+0x1f/0x96 Change-Id: I797ab83cb57842c57d4ee34acfafa5ae661333f6 Reported-by: syzbot Cc: Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Git-commit: af3ff8045bbf3e32f1a448542e73abb4c8ceb6f1) Signed-off-by: Dennis Cagle --- crypto/hmac.c | 6 +++++- crypto/shash.c | 5 +++-- include/crypto/internal/hash.h | 8 ++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/crypto/hmac.c b/crypto/hmac.c index 72e38c098bb3..ba07fb6221ae 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -194,11 +194,15 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) salg = shash_attr_alg(tb[1], 0, 0); if (IS_ERR(salg)) return PTR_ERR(salg); + alg = &salg->base; + /* The underlying hash algorithm must be unkeyed */ err = -EINVAL; + if (crypto_shash_alg_has_setkey(salg)) + goto out_put_alg; + ds = salg->digestsize; ss = salg->statesize; - alg = &salg->base; if (ds > alg->cra_blocksize || ss < alg->cra_blocksize) goto out_put_alg; diff --git a/crypto/shash.c b/crypto/shash.c index 03fbcd4a82c4..4ac57f5694fc 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -24,11 +24,12 @@ static const struct crypto_type crypto_shash_type; -static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, - unsigned int keylen) +int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) { return -ENOSYS; } +EXPORT_SYMBOL_GPL(shash_no_setkey); static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key, unsigned int keylen) diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index a25414ce2898..9779c35f8454 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -83,6 +83,14 @@ int ahash_register_instance(struct crypto_template *tmpl, struct ahash_instance *inst); void ahash_free_instance(struct crypto_instance *inst); +int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen); + +static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg) +{ + return alg->setkey != shash_no_setkey; +} + int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn, struct hash_alg_common *alg, struct crypto_instance *inst); From 6a73659eba330daf5277cb6251ee9a0771f43180 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Mon, 11 Dec 2017 22:48:41 +0100 Subject: [PATCH 024/392] USB: core: only clean up what we allocated When cleaning up the configurations, make sure we only free the number of configurations and interfaces that we could have allocated. Change-Id: I07a2ddd088264030544284ad9680cd6d2b538d21 Reported-by: Andrey Konovalov Cc: stable Signed-off-by: Greg Kroah-Hartman Git-commit: 32fd87b3bbf5f7a045546401dfe2894dbbf4d8c3 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Srinivasa Rao Kuppala --- drivers/usb/core/config.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 9a6cbaa0e7af..177079ae5941 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -641,18 +641,21 @@ void usb_destroy_configuration(struct usb_device *dev) return; if (dev->rawdescriptors) { - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) + for (i = 0; i < dev->descriptor.bNumConfigurations && + i < USB_MAXCONFIG; i++) kfree(dev->rawdescriptors[i]); kfree(dev->rawdescriptors); dev->rawdescriptors = NULL; } - for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { + for (c = 0; c < dev->descriptor.bNumConfigurations && + c < USB_MAXCONFIG; c++) { struct usb_host_config *cf = &dev->config[c]; kfree(cf->string); - for (i = 0; i < cf->desc.bNumInterfaces; i++) { + for (i = 0; i < cf->desc.bNumInterfaces && + i < USB_MAXINTERFACES; i++) { if (cf->intf_cache[i]) kref_put(&cf->intf_cache[i]->ref, usb_release_interface_cache); From e1cb890d77cb3df4e0410f8a3985829808d43753 Mon Sep 17 00:00:00 2001 From: Mike Maloney Date: Wed, 10 Jan 2018 12:45:10 -0500 Subject: [PATCH 025/392] ipv6: fix udpv6 sendmsg crash caused by too small MTU [ Upstream commit 749439bfac6e1a2932c582e2699f91d329658196 ] The logic in __ip6_append_data() assumes that the MTU is at least large enough for the headers. A device's MTU may be adjusted after being added while sendmsg() is processing data, resulting in __ip6_append_data() seeing any MTU. For an mtu smaller than the size of the fragmentation header, the math results in a negative 'maxfraglen', which causes problems when refragmenting any previous skb in the skb_write_queue, leaving it possibly malformed. Instead sendmsg returns EINVAL when the mtu is calculated to be less than IPV6_MIN_MTU. Found by syzkaller: kernel BUG at ./include/linux/skbuff.h:2064! invalid opcode: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 1 PID: 14216 Comm: syz-executor5 Not tainted 4.13.0-rc4+ #2 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 task: ffff8801d0b68580 task.stack: ffff8801ac6b8000 RIP: 0010:__skb_pull include/linux/skbuff.h:2064 [inline] RIP: 0010:__ip6_make_skb+0x18cf/0x1f70 net/ipv6/ip6_output.c:1617 RSP: 0018:ffff8801ac6bf570 EFLAGS: 00010216 RAX: 0000000000010000 RBX: 0000000000000028 RCX: ffffc90003cce000 RDX: 00000000000001b8 RSI: ffffffff839df06f RDI: ffff8801d9478ca0 RBP: ffff8801ac6bf780 R08: ffff8801cc3f1dbc R09: 0000000000000000 R10: ffff8801ac6bf7a0 R11: 43cb4b7b1948a9e7 R12: ffff8801cc3f1dc8 R13: ffff8801cc3f1d40 R14: 0000000000001036 R15: dffffc0000000000 FS: 00007f43d740c700(0000) GS:ffff8801dc100000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f7834984000 CR3: 00000001d79b9000 CR4: 00000000001406e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: ip6_finish_skb include/net/ipv6.h:911 [inline] udp_v6_push_pending_frames+0x255/0x390 net/ipv6/udp.c:1093 udpv6_sendmsg+0x280d/0x31a0 net/ipv6/udp.c:1363 inet_sendmsg+0x11f/0x5e0 net/ipv4/af_inet.c:762 sock_sendmsg_nosec net/socket.c:633 [inline] sock_sendmsg+0xca/0x110 net/socket.c:643 SYSC_sendto+0x352/0x5a0 net/socket.c:1750 SyS_sendto+0x40/0x50 net/socket.c:1718 entry_SYSCALL_64_fastpath+0x1f/0xbe RIP: 0033:0x4512e9 RSP: 002b:00007f43d740bc08 EFLAGS: 00000216 ORIG_RAX: 000000000000002c RAX: ffffffffffffffda RBX: 00000000007180a8 RCX: 00000000004512e9 RDX: 000000000000002e RSI: 0000000020d08000 RDI: 0000000000000005 RBP: 0000000000000086 R08: 00000000209c1000 R09: 000000000000001c R10: 0000000000040800 R11: 0000000000000216 R12: 00000000004b9c69 R13: 00000000ffffffff R14: 0000000000000005 R15: 00000000202c2000 Code: 9e 01 fe e9 c5 e8 ff ff e8 7f 9e 01 fe e9 4a ea ff ff 48 89 f7 e8 52 9e 01 fe e9 aa eb ff ff e8 a8 b6 cf fd 0f 0b e8 a1 b6 cf fd <0f> 0b 49 8d 45 78 4d 8d 45 7c 48 89 85 78 fe ff ff 49 8d 85 ba RIP: __skb_pull include/linux/skbuff.h:2064 [inline] RSP: ffff8801ac6bf570 RIP: __ip6_make_skb+0x18cf/0x1f70 net/ipv6/ip6_output.c:1617 RSP: ffff8801ac6bf570 Change-Id: I769108bffa68a0af77db68b3565a1ccb290fff85 Reported-by: syzbot Signed-off-by: Mike Maloney Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Git-commit: fd3030090c8debb485d3867c17f691cf1af207f6 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git Signed-off-by: Tejaswi Tanikella --- net/ipv6/ip6_output.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 81118c1ddf89..0ce09b80b94c 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1214,14 +1214,16 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, np->cork.tclass = tclass; if (rt->dst.flags & DST_XFRM_TUNNEL) mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? - rt->dst.dev->mtu : dst_mtu(&rt->dst); + READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst); else mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? - rt->dst.dev->mtu : dst_mtu(rt->dst.path); + READ_ONCE(rt->dst.dev->mtu) : dst_mtu(rt->dst.path); if (np->frag_size < mtu) { if (np->frag_size) mtu = np->frag_size; } + if (mtu < IPV6_MIN_MTU) + return -EINVAL; cork->fragsize = mtu; if (dst_allfrag(rt->dst.path)) cork->flags |= IPCORK_ALLFRAG; From 5c04df7212ac54204bfe15a1eed58b51f4ed9980 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Tue, 16 Jan 2018 13:42:30 -0800 Subject: [PATCH 026/392] ANDROID: Bluetooth: hidp: buffer overflow in hidp_process_report The buffer length is unsigned at all layers, but gets cast to int and checked in hidp_process_report and can lead to a buffer overflow. Switch len parameter to unsigned int to resolve issue. Signed-off-by: Mark Salyzyn Fixes: 678af93e46ac10318b54f2f0c9abbdfe75c4e078 ("HID: Bluetooth: hidp: make sure input buffers are big enough") Bug: 65853588 Change-Id: I779ce783ae7c3bce8c5a66c0954ef31347e42cfc Git-repo: https://android.googlesource.com/kernel/msm Git-commit: 34c56d552bffcaefa84975bea0e55fb4481964fd Signed-off-by: Dennis Cagle --- net/bluetooth/hidp/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 99624495f6c2..3af082bf7c64 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -416,8 +416,8 @@ static void hidp_del_timer(struct hidp_session *session) del_timer(&session->timer); } -static void hidp_process_report(struct hidp_session *session, - int type, const u8 *data, int len, int intr) +static void hidp_process_report(struct hidp_session *session, int type, + const u8 *data, unsigned int len, int intr) { if (len > HID_MAX_BUFFER_SIZE) len = HID_MAX_BUFFER_SIZE; From 55f96b3f348933a1dd10cc8cefa02c37909a44cf Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Wed, 22 Nov 2017 17:38:27 +0530 Subject: [PATCH 027/392] ARM: dts: msm: add afe_loopback_tx back-end dai for apq8009 Add afe_loopback_tx back-end dai for supporting afe loopback to get EC reference data. CRs-Fixed: 2147850 Change-Id: I60686088682d18db04e13b2c1878620ea059b6c5 Signed-off-by: Surendar karka --- arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi | 7 +++++-- arch/arm/boot/dts/qcom/msm8909.dtsi | 5 +++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi b/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi index 57c3db93bb01..84589e813761 100644 --- a/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi +++ b/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi @@ -25,6 +25,7 @@ qcom,model = "apq8009-tashalite-snd-card"; qcom,msm-mbhc-hphl-swh = <0>; qcom,msm-mbhc-gnd-swh = <0>; + qcom,afe-rxtx-lb; qcom,msm-mclk-freq = <9600000>; qcom,msm-hs-micbias-type = "internal"; qcom,audio-routing = @@ -87,7 +88,8 @@ <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music_2_rx>, <&bt_sco_rx>, - <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>; + <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>, + <&afe_loopback_tx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", @@ -101,7 +103,8 @@ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", - "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293"; + "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293", + "msm-dai-q6-dev.24577"; asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; qcom,wsa-max-devs = <2>; diff --git a/arch/arm/boot/dts/qcom/msm8909.dtsi b/arch/arm/boot/dts/qcom/msm8909.dtsi index 34a8cccbd5a4..334a0a11e1db 100644 --- a/arch/arm/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909.dtsi @@ -1727,6 +1727,11 @@ qcom,msm-dai-q6-dev-id = <240>; }; + afe_loopback_tx: qcom,msm-dai-q6-afe-loopback-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <24577>; + }; + incall_record_rx: qcom,msm-dai-q6-incall-record-rx { compatible = "qcom,msm-dai-q6-dev"; qcom,msm-dai-q6-dev-id = <32771>; From 827d2cc7988323cd2ef2fe76a91ce3874b60fb9b Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Tue, 9 Jan 2018 14:54:19 +0530 Subject: [PATCH 028/392] ASoC: audio-ext-clk: enable lpass_mclk for LPASS_CLK_VER_2 Sound card is not getting detected as mclk ID is not properly set for AVS service version LPASS_CLK_VER_2. Enable lpass_mclk for LPASS_CLK_VER_2 AVS service version. CRs-Fixed: 2169190 Change-Id: I4c4545a75bc5bbdfd86a36989ca20462292c94ec Signed-off-by: Surendar karka --- sound/soc/codecs/audio-ext-clk.c | 69 +++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/audio-ext-clk.c b/sound/soc/codecs/audio-ext-clk.c index fda1158682d9..4004fa74c9ba 100644 --- a/sound/soc/codecs/audio-ext-clk.c +++ b/sound/soc/codecs/audio-ext-clk.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -229,31 +229,62 @@ static int audio_ext_set_lpass_mclk_v1(struct clk *clk, return ret; } -static int audio_ext_set_lpass_mclk_v2(enum clk_enablement enable) +static int audio_ext_set_lpass_mclk_v2(struct clk *clk, + enum clk_enablement enable) { struct afe_clk_set m_clk = lpass_default2; struct afe_clk_set ibit_clk = lpass_default2; - int ret = 0; + struct audio_ext_lpass_mclk *audio_lpass_mclk; + int ret = 0, val = 0; pr_debug("%s: Setting clock using v2, enable(%d)\n", __func__, enable); - /* Set both mclk and ibit clocks when using LPASS_CLK_VER_2 */ - m_clk.enable = enable; - ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, &m_clk); - if (ret < 0) { - pr_err("%s: afe_set_lpass_clock_v2 failed for mclk_3 with ret %d\n", - __func__, ret); + audio_lpass_mclk = container_of(clk, struct audio_ext_lpass_mclk, c); + if (audio_lpass_mclk == NULL) { + pr_err("%s: audio_lpass_mclk is NULL\n", __func__); + ret = -EINVAL; goto done; } - ibit_clk.clk_id = Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT; - ibit_clk.clk_freq_in_hz = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; - ibit_clk.enable = enable; - ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, &ibit_clk); - if (ret < 0) { - pr_err("%s: afe_set_lpass_clock_v2 failed for ibit with ret %d\n", - __func__, ret); - goto err_ibit_clk_set; + if (!audio_lpass_mclk->lpass_clock) { + /* Set both mclk and ibit clocks when using LPASS_CLK_VER_2 */ + m_clk.enable = enable; + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, + &m_clk); + if (ret < 0) { + pr_err("%s: afe_set_lpass_clock_v2 failed for mclk_3\n" + "with ret %d\n", __func__, ret); + goto done; + } + + ibit_clk.clk_id = Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT; + ibit_clk.clk_freq_in_hz = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; + ibit_clk.enable = enable; + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, + &ibit_clk); + if (ret < 0) { + pr_err("%s: afe_set_lpass_clock_v2 failed for ibit\n" + "with ret %d\n", __func__, ret); + goto err_ibit_clk_set; + } + } else { + if (audio_lpass_mclk->lpass_csr_gpio_mux_spkrctl_vaddr && + enable) { + val = ioread32(audio_lpass_mclk-> + lpass_csr_gpio_mux_spkrctl_vaddr); + val = val | 0x00000002; + iowrite32(val, audio_lpass_mclk-> + lpass_csr_gpio_mux_spkrctl_vaddr); + } + + digital_cdc_core_clk.enable = enable; + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX, + &digital_cdc_core_clk); + if (ret < 0) { + pr_err("%s: afe_set_digital_codec_core_clock failed\n" + " with ret %d\n", __func__, ret); + goto done; + } } ret = 0; @@ -299,7 +330,7 @@ static int audio_ext_lpass_mclk_prepare(struct clk *clk) lpass_clk_ver = afe_get_lpass_clk_ver(); if (lpass_clk_ver >= LPASS_CLK_VER_2) - ret = audio_ext_set_lpass_mclk_v2(CLK_ENABLE); + ret = audio_ext_set_lpass_mclk_v2(clk, CLK_ENABLE); else ret = audio_ext_set_lpass_mclk_v1(clk, CLK_ENABLE); @@ -336,7 +367,7 @@ static void audio_ext_lpass_mclk_unprepare(struct clk *clk) lpass_clk_ver = afe_get_lpass_clk_ver(); if (lpass_clk_ver >= LPASS_CLK_VER_2) - ret = audio_ext_set_lpass_mclk_v2(CLK_DISABLE); + ret = audio_ext_set_lpass_mclk_v2(clk, CLK_DISABLE); else ret = audio_ext_set_lpass_mclk_v1(clk, CLK_DISABLE); From 4e9c96ee674d633c224efb499a8b037fded1899f Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Thu, 28 Dec 2017 16:28:05 +0530 Subject: [PATCH 029/392] ASoC: wcd9335: set codec TX path to tri-state I2S TX line is shared between the Codec and TDM mics, tristate the WCD mics to avoid PCM interference as the end product uses only TDM mics. CRs-Fixed: 2164870 Change-Id: I167e8af416defc631ca10a9e6e0cbe565d5a8acd Signed-off-by: Surendar karka --- .../devicetree/bindings/sound/taiko_codec.txt | 4 +++ drivers/mfd/wcd9xxx-core.c | 4 ++- include/linux/mfd/wcd9xxx/pdata.h | 3 +- sound/soc/codecs/wcd9335.c | 28 ++++++++++++++++++- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt index 90bef273363d..5f8d2938b187 100644 --- a/Documentation/devicetree/bindings/sound/taiko_codec.txt +++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt @@ -536,6 +536,10 @@ Tasha audio CODEC in I2C mode - qcom,cdc-dmic-sample-rate - Specifies dmic sample rate. - qcom,cdc-variant - Specifies codec variant. + - qcom,wcd9xxx-mic-tristate: For chipsets where I2S TX line is shared between + the Codec and TDM mics, tristate the WCD mics to + avoid PCM interference as the end product uses + only TDM mics. Example: i2c_3: i2c@78B7000 { /* BLSP1 QUP3 */ diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c index de1b1ba28f83..c8c5efd3c4b9 100644 --- a/drivers/mfd/wcd9xxx-core.c +++ b/drivers/mfd/wcd9xxx-core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2881,6 +2881,8 @@ static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev) else pdata->cdc_variant = WCD9XXX; } + pdata->wcd9xxx_mic_tristate = of_property_read_bool(dev->of_node, + "qcom,wcd9xxx-mic-tristate"); return pdata; err: diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h index f3cbfbe80c7c..d876386d8ace 100644 --- a/include/linux/mfd/wcd9xxx/pdata.h +++ b/include/linux/mfd/wcd9xxx/pdata.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -192,6 +192,7 @@ struct wcd9xxx_pdata { u32 mic_unmute_delay; enum codec_variant cdc_variant; u16 use_pinctrl; + bool wcd9xxx_mic_tristate; }; #endif diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 7ad240383596..cf5af8ea6a3d 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -851,6 +851,15 @@ static const struct tasha_reg_mask_val tasha_spkr_mode1[] = { {WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44}, }; +static const struct tasha_reg_mask_val tasha_high_impedance[] = { + {WCD9335_TLMM_I2S_TX_SD0_PINCFG, 0x1F, 0x0C}, + {WCD9335_TLMM_I2S_TX_SD1_PINCFG, 0x1F, 0x0C}, + {WCD9335_TLMM_I2S_TX_SCK_PINCFG, 0x1F, 0x0C}, + {WCD9335_TLMM_I2S_TX_WS_PINCFG, 0x1F, 0x0C}, + {WCD9335_TEST_DEBUG_PIN_CTL_OE_1, 0xE0, 0xE0}, + {WCD9335_TEST_DEBUG_PIN_CTL_OE_2, 0x01, 0x01}, +}; + /** * tasha_set_spkr_gain_offset - offset the speaker path * gain with the given offset value. @@ -954,6 +963,20 @@ static void tasha_cdc_sido_ccl_enable(struct tasha_priv *tasha, bool ccl_flag) } } +static void tasha_set_high_impedance_mode(struct snd_soc_codec *codec) +{ + const struct tasha_reg_mask_val *regs; + int i, size; + + dev_dbg(codec->dev, "%s: setting TX I2S in Hi-Z mode\n", __func__); + regs = tasha_high_impedance; + size = ARRAY_SIZE(tasha_high_impedance); + + for (i = 0; i < size; i++) + snd_soc_update_bits(codec, regs[i].reg, + regs[i].mask, regs[i].val); +} + static bool tasha_cdc_is_svs_enabled(struct tasha_priv *tasha) { if (TASHA_IS_2_0(tasha->wcd9xxx->version) && @@ -13941,6 +13964,9 @@ static int tasha_codec_probe(struct snd_soc_codec *codec) mutex_unlock(&codec->mutex); snd_soc_dapm_sync(dapm); + if (pdata->wcd9xxx_mic_tristate) + tasha_set_high_impedance_mode(codec); + return ret; err_pdata: From 4ca5fad79596256e84afa3d40fb3519defd646b5 Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Mon, 27 Nov 2017 18:07:15 +0530 Subject: [PATCH 030/392] ASoC:msm: Add routing controls for SVA to work on BG -Enable use of PRI_TDM_TX2 an PRI_TDM_TX_3 ports for SVA usecases. Change-Id: I43d0c7df8592d5b093dbce4c54d309374d479ebb Signed-off-by: Ashish Jain --- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 80 +++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 3b280cebe1ff..1d1b5e669f5f 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -94,13 +94,16 @@ enum { #define SLIMBUS_5_TX_TEXT "SLIMBUS_5_TX" #define TERT_MI2S_TX_TEXT "TERT_MI2S_TX" #define QUAT_MI2S_TX_TEXT "QUAT_MI2S_TX" +#define PRI_TDM_TX_3_TEXT "PRI_TDM_TX_3" +#define PRI_TDM_TX_2_TEXT "PRI_TDM_TX_2" #define ADM_LSM_TX_TEXT "ADM_LSM_TX" #define LSM_FUNCTION_TEXT "LSM Function" static const char * const lsm_port_text[] = { "None", SLIMBUS_0_TX_TEXT, SLIMBUS_1_TX_TEXT, SLIMBUS_2_TX_TEXT, SLIMBUS_3_TX_TEXT, SLIMBUS_4_TX_TEXT, SLIMBUS_5_TX_TEXT, - TERT_MI2S_TX_TEXT, QUAT_MI2S_TX_TEXT, ADM_LSM_TX_TEXT + TERT_MI2S_TX_TEXT, QUAT_MI2S_TX_TEXT, ADM_LSM_TX_TEXT, + PRI_TDM_TX_2_TEXT, PRI_TDM_TX_3_TEXT, }; struct msm_pcm_route_bdai_pp_params { @@ -2039,6 +2042,12 @@ static int msm_routing_lsm_port_put(struct snd_kcontrol *kcontrol, case 9: lsm_port = ADM_LSM_PORT_ID; break; + case 10: + lsm_port = AFE_PORT_ID_PRIMARY_TDM_TX_2; + break; + case 11: + lsm_port = AFE_PORT_ID_PRIMARY_TDM_TX_3; + break; default: pr_err("Default lsm port"); break; @@ -8794,6 +8803,12 @@ static const struct snd_kcontrol_new lsm1_mixer_controls[] = { SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm2_mixer_controls[] = { @@ -8818,6 +8833,12 @@ static const struct snd_kcontrol_new lsm2_mixer_controls[] = { SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm3_mixer_controls[] = { @@ -8842,6 +8863,12 @@ static const struct snd_kcontrol_new lsm3_mixer_controls[] = { SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm4_mixer_controls[] = { @@ -8866,6 +8893,12 @@ static const struct snd_kcontrol_new lsm4_mixer_controls[] = { SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm5_mixer_controls[] = { @@ -8890,6 +8923,12 @@ static const struct snd_kcontrol_new lsm5_mixer_controls[] = { SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm6_mixer_controls[] = { @@ -8914,6 +8953,12 @@ static const struct snd_kcontrol_new lsm6_mixer_controls[] = { SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm7_mixer_controls[] = { @@ -8938,6 +8983,12 @@ static const struct snd_kcontrol_new lsm7_mixer_controls[] = { SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm8_mixer_controls[] = { @@ -8962,6 +9013,12 @@ static const struct snd_kcontrol_new lsm8_mixer_controls[] = { SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, + msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new slim_fm_switch_mixer_controls = @@ -9056,6 +9113,10 @@ static const struct snd_kcontrol_new lsm_controls[] = { msm_routing_lsm_func_get, msm_routing_lsm_func_put), SOC_ENUM_EXT(QUAT_MI2S_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum, msm_routing_lsm_func_get, msm_routing_lsm_func_put), + SOC_ENUM_EXT(PRI_TDM_TX_2_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum, + msm_routing_lsm_func_get, msm_routing_lsm_func_put), + SOC_ENUM_EXT(PRI_TDM_TX_3_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum, + msm_routing_lsm_func_get, msm_routing_lsm_func_put), /* kcontrol of lsm_port */ SOC_ENUM_EXT("LSM1 Port", lsm_port_enum, msm_routing_lsm_port_get, @@ -12272,6 +12333,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"LSM1 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"}, {"LSM1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, {"LSM1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"LSM1 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, + {"LSM1 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, {"LSM1_UL_HL", NULL, "LSM1 Mixer"}, {"LSM2 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"}, @@ -12281,6 +12344,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"LSM2 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"}, {"LSM2 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, {"LSM2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"LSM2 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, + {"LSM2 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, + {"LSM2_UL_HL", NULL, "LSM2 Mixer"}, @@ -12291,6 +12357,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"LSM3 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"}, {"LSM3 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, {"LSM3 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"LSM3 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, + {"LSM3 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, {"LSM3_UL_HL", NULL, "LSM3 Mixer"}, @@ -12301,6 +12369,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"LSM4 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"}, {"LSM4 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, {"LSM4 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"LSM4 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, + {"LSM4 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, {"LSM4_UL_HL", NULL, "LSM4 Mixer"}, {"LSM5 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"}, @@ -12310,6 +12380,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"LSM5 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"}, {"LSM5 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, {"LSM5 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"LSM5 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, + {"LSM5 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, {"LSM5_UL_HL", NULL, "LSM5 Mixer"}, {"LSM6 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"}, @@ -12318,6 +12390,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"LSM6 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"}, {"LSM6 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"}, {"LSM6 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"LSM6 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, + {"LSM6 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, {"LSM6_UL_HL", NULL, "LSM6 Mixer"}, @@ -12327,6 +12401,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"LSM7 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"}, {"LSM7 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"}, {"LSM7 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"LSM7 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, + {"LSM7 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, {"LSM7_UL_HL", NULL, "LSM7 Mixer"}, @@ -12336,6 +12412,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"LSM8 Mixer", "SLIMBUS_4_TX", "SLIMBUS_4_TX"}, {"LSM8 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"}, {"LSM8 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"LSM8 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, + {"LSM8 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, {"LSM8_UL_HL", NULL, "LSM8 Mixer"}, From f67620f4ff0a175f35010de4c1d8375e2560a309 Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Tue, 4 Oct 2016 15:57:08 +0530 Subject: [PATCH 031/392] ASoC: msm: qdsp6v2: add support for latest version of media format command Add support for ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 command. This command adds support to playback/record 32 bit data in 32 bit word and also provides a way to inform DSP about the endianness of the data. CRs-Fixed: 2129947 Change-Id: I3b013bedde8ccfa97a02e255e237df0cf2de13b8 Signed-off-by: Ashish Jain Signed-off-by: Dhanalakshmi Siddani --- include/sound/apr_audio-v2.h | 137 +++++++++- include/sound/q6asm-v2.h | 61 ++++- sound/soc/msm/qdsp6v2/q6asm.c | 462 ++++++++++++++++++++++++++++++++-- 3 files changed, 638 insertions(+), 22 deletions(-) diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 6f88d5348f2f..d7f7212a74ca 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -3391,6 +3391,8 @@ struct asm_softvolume_params { #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 0x00010DDC +#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 0x0001320C + #define ASM_MEDIA_FMT_EVRCB_FS 0x00010BEF #define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0 @@ -3493,6 +3495,56 @@ struct asm_multi_channel_pcm_fmt_blk_v3 { */ } __packed; +struct asm_multi_channel_pcm_fmt_blk_v4 { + uint16_t num_channels; +/* + * Number of channels + * Supported values: 1 to 8 + */ + + uint16_t bits_per_sample; +/* + * Number of bits per sample per channel + * Supported values: 16, 24, 32 + */ + + uint32_t sample_rate; +/* + * Number of samples per second + * Supported values: 2000 to 48000, 96000,192000 Hz + */ + + uint16_t is_signed; +/* Flag that indicates that PCM samples are signed (1) */ + + uint16_t sample_word_size; +/* + * Size in bits of the word that holds a sample of a channel. + * Supported values: 12,24,32 + */ + + uint8_t channel_mapping[8]; +/* + * Each element, i, in the array describes channel i inside the buffer where + * 0 <= i < num_channels. Unused channels are set to 0. + */ + uint16_t endianness; +/* + * Flag to indicate the endianness of the pcm sample + * Supported values: 0 - Little endian (all other formats) + * 1 - Big endian (AIFF) + */ + uint16_t mode; +/* + * Mode to provide additional info about the pcm input data. + * Supported values: 0 - Default QFs (Q15 for 16b, Q23 for packed 24b, + * Q31 for unpacked 24b or 32b) + * 15 - for 16 bit + * 23 - for 24b packed or 8.24 format + * 31 - for 24b unpacked or 32bit + */ +} __packed; + /* * Payload of the multichannel PCM configuration parameters in * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 media format. @@ -3503,6 +3555,16 @@ struct asm_multi_channel_pcm_fmt_blk_param_v3 { struct asm_multi_channel_pcm_fmt_blk_v3 param; } __packed; +/* + * Payload of the multichannel PCM configuration parameters in + * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 media format. + */ +struct asm_multi_channel_pcm_fmt_blk_param_v4 { + struct apr_hdr hdr; + struct asm_data_cmd_media_fmt_update_v2 fmt_blk; + struct asm_multi_channel_pcm_fmt_blk_v4 param; +} __packed; + struct asm_stream_cmd_set_encdec_param { u32 param_id; /* ID of the parameter. */ @@ -3538,6 +3600,79 @@ struct asm_dec_ddp_endp_param_v2 { int endp_param_value; } __packed; +/* + * Payload of the multichannel PCM encoder configuration parameters in + * the ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4 media format. + */ + +struct asm_multi_channel_pcm_enc_cfg_v4 { + struct apr_hdr hdr; + struct asm_stream_cmd_set_encdec_param encdec; + struct asm_enc_cfg_blk_param_v2 encblk; + uint16_t num_channels; + /* + * Number of PCM channels. + * @values + * - 0 -- Native mode + * - 1 -- 8 channels + * Native mode indicates that encoding must be performed with the number + * of channels at the input. + */ + uint16_t bits_per_sample; + /* + * Number of bits per sample per channel. + * @values 16, 24 + */ + uint32_t sample_rate; + /* + * Number of samples per second. + * @values 0, 8000 to 48000 Hz + * A value of 0 indicates the native sampling rate. Encoding is + * performed at the input sampling rate. + */ + uint16_t is_signed; + /* + * Flag that indicates the PCM samples are signed (1). Currently, only + * signed PCM samples are supported. + */ + uint16_t sample_word_size; + /* + * The size in bits of the word that holds a sample of a channel. + * @values 16, 24, 32 + * 16-bit samples are always placed in 16-bit words: + * sample_word_size = 1. + * 24-bit samples can be placed in 32-bit words or in consecutive + * 24-bit words. + * - If sample_word_size = 32, 24-bit samples are placed in the + * most significant 24 bits of a 32-bit word. + * - If sample_word_size = 24, 24-bit samples are placed in + * 24-bit words. @tablebulletend + */ + uint8_t channel_mapping[8]; + /* + * Channel mapping array expected at the encoder output. + * Channel[i] mapping describes channel i inside the buffer, where + * 0 @le i < num_channels. All valid used channels must be present at + * the beginning of the array. + * If Native mode is set for the channels, this field is ignored. + * @values See Section @xref{dox:PcmChannelDefs} + */ + uint16_t endianness; + /* + * Flag to indicate the endianness of the pcm sample + * Supported values: 0 - Little endian (all other formats) + * 1 - Big endian (AIFF) + */ + uint16_t mode; + /* + * Mode to provide additional info about the pcm input data. + * Supported values: 0 - Default QFs (Q15 for 16b, Q23 for packed 24b, + * Q31 for unpacked 24b or 32b) + * 15 - for 16 bit + * 23 - for 24b packed or 8.24 format + * 31 - for 24b unpacked or 32bit + */ +} __packed; /* * Payload of the multichannel PCM encoder configuration parameters in diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index 7771f2468eee..d58cf56c3eb9 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -103,6 +103,24 @@ #define ASM_SHIFT_GAPLESS_MODE_FLAG 31 #define ASM_SHIFT_LAST_BUFFER_FLAG 30 +#define ASM_LITTLE_ENDIAN 0 +#define ASM_BIG_ENDIAN 1 + +/* PCM_MEDIA_FORMAT_Version */ +enum { + PCM_MEDIA_FORMAT_V2 = 0, + PCM_MEDIA_FORMAT_V3, + PCM_MEDIA_FORMAT_V4, +}; + +/* PCM format modes in DSP */ +enum { + DEFAULT_QF = 0, + Q15 = 15, + Q23 = 23, + Q31 = 31, +}; + /* payload structure bytes */ #define READDONE_IDX_STATUS 0 #define READDONE_IDX_BUFADD_LSW 1 @@ -270,6 +288,9 @@ int q6asm_open_shared_io(struct audio_client *ac, int q6asm_open_write_v3(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample); +int q6asm_open_write_v4(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample); + int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, int32_t stream_id, bool is_gapless_mode); @@ -278,6 +299,10 @@ int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, int32_t stream_id, bool is_gapless_mode); +int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample, int32_t stream_id, + bool is_gapless_mode); + int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format, uint32_t passthrough_flag); @@ -386,6 +411,13 @@ int q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac, bool use_back_flavor, u8 *channel_map, uint16_t sample_word_size); +int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, bool use_default_chmap, + bool use_back_flavor, u8 *channel_map, + uint16_t sample_word_size, uint16_t endianness, + uint16_t mode); + int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, uint32_t rate, uint32_t channels, uint16_t bits_per_sample); @@ -395,6 +427,13 @@ int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac, uint16_t bits_per_sample, uint16_t sample_word_size); +int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode); + int q6asm_set_encdec_chan_map(struct audio_client *ac, uint32_t num_channels); @@ -444,6 +483,17 @@ int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac, char *channel_map, uint16_t sample_word_size); +int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac, + uint32_t rate, + uint32_t channels, + uint16_t bits_per_sample, + int stream_id, + bool use_default_chmap, + char *channel_map, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode); + int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, bool use_default_chmap, char *channel_map); @@ -461,6 +511,15 @@ int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac, uint16_t bits_per_sample, uint16_t sample_word_size); +int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + bool use_default_chmap, + char *channel_map, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode); + int q6asm_media_format_block_aac(struct audio_client *ac, struct asm_aac_cfg *cfg); diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index aef23da39326..c986db20c2d1 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -134,6 +134,24 @@ static int out_cold_index; static char *out_buffer; static char *in_buffer; +static inline uint32_t q6asm_get_pcm_format_id(uint32_t media_format_block_ver) +{ + uint32_t pcm_format_id; + + switch (media_format_block_ver) { + case PCM_MEDIA_FORMAT_V4: + pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4; + break; + case PCM_MEDIA_FORMAT_V3: + pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3; + break; + case PCM_MEDIA_FORMAT_V2: + default: + pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + break; + } + return pcm_format_id; +} static int audio_output_latency_dbgfs_open(struct inode *inode, struct file *file) @@ -2342,7 +2360,8 @@ static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr, static int __q6asm_open_read(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, - bool use_v3_format, bool ts_mode) + uint32_t pcm_format_block_ver, + bool ts_mode) { int rc = 0x00; struct asm_stream_cmd_open_read_v3 open; @@ -2382,12 +2401,9 @@ static int __q6asm_open_read(struct audio_client *ac, switch (format) { case FORMAT_LINEAR_PCM: open.mode_flags |= 0x00; + open.enc_cfg_id = q6asm_get_pcm_format_id(pcm_format_block_ver); if (ts_mode) open.mode_flags |= ABSOLUTE_TIMESTAMP_ENABLE; - if (use_v3_format) - open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3; - else - open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; break; case FORMAT_MPEG4_AAC: open.mode_flags |= BUFFER_META_ENABLE; @@ -2458,14 +2474,16 @@ int q6asm_open_read(struct audio_client *ac, uint32_t format) { return __q6asm_open_read(ac, format, 16, - false /*use_v3_format*/, false/*ts_mode*/); + PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/, + false/*ts_mode*/); } int q6asm_open_read_v2(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { return __q6asm_open_read(ac, format, bits_per_sample, - false /*use_v3_format*/, false/*ts_mode*/); + PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/, + false/*ts_mode*/); } /* @@ -2479,7 +2497,8 @@ int q6asm_open_read_v3(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { return __q6asm_open_read(ac, format, bits_per_sample, - true /*use_v3_format*/, false/*ts_mode*/); + PCM_MEDIA_FORMAT_V3/*media fmt block ver*/, + false/*ts_mode*/); } EXPORT_SYMBOL(q6asm_open_read_v3); @@ -2494,7 +2513,8 @@ int q6asm_open_read_v4(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample) { return __q6asm_open_read(ac, format, bits_per_sample, - true /*use_v3_format*/, true/*ts_mode*/); + PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/, + true/*ts_mode*/); } EXPORT_SYMBOL(q6asm_open_read_v4); @@ -2585,7 +2605,8 @@ int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format, static int __q6asm_open_write(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, uint32_t stream_id, - bool is_gapless_mode, bool use_v3_format) + bool is_gapless_mode, + uint32_t pcm_format_block_ver) { int rc = 0x00; struct asm_stream_cmd_open_write_v3 open; @@ -2648,11 +2669,7 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format, } switch (format) { case FORMAT_LINEAR_PCM: - if (use_v3_format) - open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3; - else - open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; - + open.dec_fmt_id = q6asm_get_pcm_format_id(pcm_format_block_ver); break; case FORMAT_MPEG4_AAC: open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2; @@ -2731,7 +2748,7 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format) { return __q6asm_open_write(ac, format, 16, ac->stream_id, false /*gapless*/, - false /*use_v3_format*/); + PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/); } int q6asm_open_write_v2(struct audio_client *ac, uint32_t format, @@ -2739,7 +2756,7 @@ int q6asm_open_write_v2(struct audio_client *ac, uint32_t format, { return __q6asm_open_write(ac, format, bits_per_sample, ac->stream_id, false /*gapless*/, - false /*use_v3_format*/); + PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/); } /* @@ -2754,17 +2771,33 @@ int q6asm_open_write_v3(struct audio_client *ac, uint32_t format, { return __q6asm_open_write(ac, format, bits_per_sample, ac->stream_id, false /*gapless*/, - true /*use_v3_format*/); + PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/); } EXPORT_SYMBOL(q6asm_open_write_v3); +/* + * q6asm_open_write_v4 - Opens audio playback session + * + * @ac: Client session handle + * @format: decoder format + * @bits_per_sample: bit width of playback session + */ +int q6asm_open_write_v4(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample) +{ + return __q6asm_open_write(ac, format, bits_per_sample, + ac->stream_id, false /*gapless*/, + PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/); +} +EXPORT_SYMBOL(q6asm_open_write_v4); + int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, int32_t stream_id, bool is_gapless_mode) { return __q6asm_open_write(ac, format, bits_per_sample, stream_id, is_gapless_mode, - false /*use_v3_format*/); + PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/); } /* @@ -2782,10 +2815,29 @@ int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format, { return __q6asm_open_write(ac, format, bits_per_sample, stream_id, is_gapless_mode, - true /*use_v3_format*/); + PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/); } EXPORT_SYMBOL(q6asm_stream_open_write_v3); +/* + * q6asm_stream_open_write_v4 - Creates audio stream for playback + * + * @ac: Client session handle + * @format: asm playback format + * @bits_per_sample: bit width of requested stream + * @stream_id: stream id of stream to be associated with this session + * @is_gapless_mode: true if gapless mode needs to be enabled + */ +int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample, int32_t stream_id, + bool is_gapless_mode) +{ + return __q6asm_open_write(ac, format, bits_per_sample, + stream_id, is_gapless_mode, + PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/); +} +EXPORT_SYMBOL(q6asm_stream_open_write_v4); + static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format, uint32_t wr_format, bool is_meta_data_mode, uint32_t bits_per_sample, @@ -3708,6 +3760,108 @@ int q6asm_set_encdec_chan_map(struct audio_client *ac, return rc; } +/* + * q6asm_enc_cfg_blk_pcm_v4 - sends encoder configuration parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @use_default_chmap: true if default channel map to be used + * @use_back_flavor: to configure back left and right channel + * @channel_map: input channel map + * @sample_word_size: Size in bits of the word that holds a sample of a channel + * @endianness: endianness of the pcm data + * @mode: Mode to provide additional info about the pcm input data + */ +int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, bool use_default_chmap, + bool use_back_flavor, u8 *channel_map, + uint16_t sample_word_size, uint16_t endianness, + uint16_t mode) +{ + struct asm_multi_channel_pcm_enc_cfg_v4 enc_cfg; + struct asm_enc_cfg_blk_param_v2 enc_fg_blk; + u8 *channel_mapping; + u32 frames_per_buf = 0; + int rc; + + if (!use_default_chmap && (channel_map == NULL)) { + pr_err("%s: No valid chan map and can't use default\n", + __func__); + rc = -EINVAL; + goto fail_cmd; + } + + pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__, + ac->session, rate, channels, + bits_per_sample, sample_word_size); + + memset(&enc_cfg, 0, sizeof(enc_cfg)); + q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE); + atomic_set(&ac->cmd_state, -1); + enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; + enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2; + enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) - + sizeof(enc_cfg.encdec); + enc_cfg.encblk.frames_per_buf = frames_per_buf; + enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size - + sizeof(enc_fg_blk); + enc_cfg.num_channels = channels; + enc_cfg.bits_per_sample = bits_per_sample; + enc_cfg.sample_rate = rate; + enc_cfg.is_signed = 1; + enc_cfg.sample_word_size = sample_word_size; + enc_cfg.endianness = endianness; + enc_cfg.mode = mode; + channel_mapping = enc_cfg.channel_mapping; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + + if (use_default_chmap) { + pr_debug("%s: setting default channel map for %d channels", + __func__, channels); + if (q6asm_map_channels(channel_mapping, channels, + use_back_flavor)) { + pr_err("%s: map channels failed %d\n", + __func__, channels); + rc = -EINVAL; + goto fail_cmd; + } + } else { + pr_debug("%s: Using pre-defined channel map", __func__); + memcpy(channel_mapping, channel_map, + PCM_FORMAT_MAX_NUM_CHANNEL); + } + + rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg); + if (rc < 0) { + pr_err("%s: Command open failed %d\n", __func__, rc); + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout opcode[0x%x]\n", + __func__, enc_cfg.hdr.opcode); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + return 0; +fail_cmd: + return rc; +} +EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v4); + /* * q6asm_enc_cfg_blk_pcm_v3 - sends encoder configuration parameters * @@ -3884,6 +4038,18 @@ int q6asm_enc_cfg_blk_pcm_v2(struct audio_client *ac, return rc; } +static int __q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + return q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels, + bits_per_sample, true, false, NULL, + sample_word_size, endianness, mode); +} + static int __q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac, uint32_t rate, uint32_t channels, uint16_t bits_per_sample, @@ -3933,6 +4099,31 @@ int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac, } EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v3); +/* + * q6asm_enc_cfg_blk_pcm_format_support_v4 - sends encoder configuration + * parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @sample_word_size: Size in bits of the word that holds a sample of a channel + * @endianness: endianness of the pcm data + * @mode: Mode to provide additional info about the pcm input data + */ +int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + return __q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels, + bits_per_sample, sample_word_size, + endianness, mode); +} +EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v4); + int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac, uint32_t rate, uint32_t channels) { @@ -4575,6 +4766,91 @@ static int __q6asm_media_format_block_pcm_v3(struct audio_client *ac, return rc; } +static int __q6asm_media_format_block_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + uint16_t bits_per_sample, + int stream_id, + bool use_default_chmap, + char *channel_map, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt; + u8 *channel_mapping; + int rc; + + pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__, + ac->session, rate, channels, + bits_per_sample, sample_word_size); + + memset(&fmt, 0, sizeof(fmt)); + q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id); + atomic_set(&ac->cmd_state, -1); + /* + * Updated the token field with stream/session for compressed playback + * Platform driver must know the the stream with which the command is + * associated + */ + if (ac->io_mode & COMPRESSED_STREAM_IO) + fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) | + (stream_id & 0xFF); + + pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n", + __func__, fmt.hdr.token, stream_id, ac->session); + + fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) - + sizeof(fmt.fmt_blk); + fmt.param.num_channels = channels; + fmt.param.bits_per_sample = bits_per_sample; + fmt.param.sample_rate = rate; + fmt.param.is_signed = 1; + fmt.param.sample_word_size = sample_word_size; + fmt.param.endianness = endianness; + fmt.param.mode = mode; + channel_mapping = fmt.param.channel_mapping; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + + if (use_default_chmap) { + if (q6asm_map_channels(channel_mapping, channels, false)) { + pr_err("%s: map channels failed %d\n", + __func__, channels); + rc = -EINVAL; + goto fail_cmd; + } + } else { + memcpy(channel_mapping, channel_map, + PCM_FORMAT_MAX_NUM_CHANNEL); + } + + rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt); + if (rc < 0) { + pr_err("%s: Comamnd open failed %d\n", __func__, rc); + rc = -EINVAL; + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout. waited for format update\n", __func__); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + return 0; +fail_cmd: + return rc; +} + int q6asm_media_format_block_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels) { @@ -4642,6 +4918,47 @@ int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac, } EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v3); +/* + * q6asm_media_format_block_pcm_format_support_v4- sends pcm decoder + * configuration parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @stream_id: stream id of stream to be associated with this session + * @use_default_chmap: true if default channel map to be used + * @channel_map: input channel map + * @sample_word_size: Size in bits of the word that holds a sample of a channel + * @endianness: endianness of the pcm data + * @mode: Mode to provide additional info about the pcm input data + */ +int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac, + uint32_t rate, + uint32_t channels, + uint16_t bits_per_sample, + int stream_id, + bool use_default_chmap, + char *channel_map, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + if (!use_default_chmap && (channel_map == NULL)) { + pr_err("%s: No valid chan map and can't use default\n", + __func__); + return -EINVAL; + } + return __q6asm_media_format_block_pcm_v4(ac, rate, + channels, bits_per_sample, stream_id, + use_default_chmap, channel_map, + sample_word_size, endianness, + mode); + +} +EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v4); + + static int __q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, bool use_default_chmap, char *channel_map, @@ -4775,6 +5092,78 @@ static int __q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac, return rc; } +static int __q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac, + uint32_t rate, + uint32_t channels, + bool use_default_chmap, + char *channel_map, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt; + u8 *channel_mapping; + int rc; + + pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__, + ac->session, rate, channels, + bits_per_sample, sample_word_size); + + memset(&fmt, 0, sizeof(fmt)); + q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE); + atomic_set(&ac->cmd_state, -1); + + fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) - + sizeof(fmt.fmt_blk); + fmt.param.num_channels = channels; + fmt.param.bits_per_sample = bits_per_sample; + fmt.param.sample_rate = rate; + fmt.param.is_signed = 1; + fmt.param.sample_word_size = sample_word_size; + fmt.param.endianness = endianness; + fmt.param.mode = mode; + channel_mapping = fmt.param.channel_mapping; + + memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL); + + if (use_default_chmap) { + if (q6asm_map_channels(channel_mapping, channels, false)) { + pr_err("%s: map channels failed %d\n", + __func__, channels); + rc = -EINVAL; + goto fail_cmd; + } + } else { + memcpy(channel_mapping, channel_map, + PCM_FORMAT_MAX_NUM_CHANNEL); + } + + rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt); + if (rc < 0) { + pr_err("%s: Comamnd open failed %d\n", __func__, rc); + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 5*HZ); + if (!rc) { + pr_err("%s: timeout. waited for format update\n", __func__); + rc = -ETIMEDOUT; + goto fail_cmd; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + return 0; +fail_cmd: + return rc; +} int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, @@ -4822,6 +5211,39 @@ int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac, } EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v3); +/* + * q6asm_media_format_block_multi_ch_pcm_v4 - sends pcm decoder configuration + * parameters + * + * @ac: Client session handle + * @rate: sample rate + * @channels: number of channels + * @bits_per_sample: bit width of encoder session + * @use_default_chmap: true if default channel map to be used + * @channel_map: input channel map + * @sample_word_size: Size in bits of the word that holds a sample of a channel + * @endianness: endianness of the pcm data + * @mode: Mode to provide additional info about the pcm input data + */ +int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac, + uint32_t rate, uint32_t channels, + bool use_default_chmap, + char *channel_map, + uint16_t bits_per_sample, + uint16_t sample_word_size, + uint16_t endianness, + uint16_t mode) +{ + return __q6asm_media_format_block_multi_ch_pcm_v4(ac, rate, channels, + use_default_chmap, + channel_map, + bits_per_sample, + sample_word_size, + endianness, + mode); +} +EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4); + static int __q6asm_media_format_block_multi_aac(struct audio_client *ac, struct asm_aac_cfg *cfg, int stream_id) { From 42ebb5a2774407b73565b2e1f023d5e98ac6c52b Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Mon, 3 Oct 2016 22:16:02 +0530 Subject: [PATCH 032/392] ASoc: msm: Enable support for 32 bit format and 384Khz Add support for 32 bit data format (SNDRV_PCM_FORMAT_S32_LE) and sampling rate of 384Khz. Also update platform drivers to use latest version of pcm media format command ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4. CRs-Fixed: 2129947 Change-Id: I6b7ea860a398a7e4dd5f7e23ac3906ff0c6f2b3e Signed-off-by: Ashish Jain Signed-off-by: Dhanalakshmi Siddani --- sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c | 16 +++++--- sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 43 +++++++++++++++------- sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h | 6 +-- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 8006ece375aa..f74582035a24 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -823,6 +823,10 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, } switch (prtd->codec_param.codec.format) { + case SNDRV_PCM_FORMAT_S32_LE: + bit_width = 32; + sample_word_size = 32; + break; case SNDRV_PCM_FORMAT_S24_LE: bit_width = 24; sample_word_size = 32; @@ -837,14 +841,16 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, sample_word_size = 16; break; } - ret = q6asm_media_format_block_pcm_format_support_v3( + ret = q6asm_media_format_block_pcm_format_support_v4( prtd->audio_client, prtd->sample_rate, prtd->num_channels, bit_width, stream_id, use_default_chmap, chmap, - sample_word_size); + sample_word_size, + ASM_LITTLE_ENDIAN, + DEFAULT_QF); if (ret < 0) pr_err("%s: CMD Format block failed\n", __func__); @@ -1112,7 +1118,7 @@ static int msm_compr_configure_dsp_for_playback } else { pr_debug("%s: stream_id %d bits_per_sample %d\n", __func__, ac->stream_id, bits_per_sample); - ret = q6asm_stream_open_write_v3(ac, + ret = q6asm_stream_open_write_v4(ac, prtd->codec, bits_per_sample, ac->stream_id, prtd->gapless_state.use_dsp_gapless_mode); @@ -2334,7 +2340,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) pr_debug("%s: open_write stream_id %d bits_per_sample %d", __func__, stream_id, bits_per_sample); - rc = q6asm_stream_open_write_v3(prtd->audio_client, + rc = q6asm_stream_open_write_v4(prtd->audio_client, prtd->codec, bits_per_sample, stream_id, prtd->gapless_state.use_dsp_gapless_mode); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index eefae71a27bf..8f4961feb604 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -68,10 +68,11 @@ static struct snd_pcm_hardware msm_pcm_hardware_capture = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), - .rates = SNDRV_PCM_RATE_8000_48000, + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), + .rates = SNDRV_PCM_RATE_8000_384000, .rate_min = 8000, - .rate_max = 48000, + .rate_max = 384000, .channels_min = 1, .channels_max = 4, .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * @@ -91,10 +92,11 @@ static struct snd_pcm_hardware msm_pcm_hardware_playback = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), - .rates = SNDRV_PCM_RATE_8000_192000, + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), + .rates = SNDRV_PCM_RATE_8000_384000, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, .channels_min = 1, .channels_max = 8, .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * @@ -109,7 +111,7 @@ static struct snd_pcm_hardware msm_pcm_hardware_playback = { /* Conventional and unconventional sample rate supported */ static unsigned int supported_sample_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, - 88200, 96000, 176400, 192000 + 88200, 96000, 176400, 192000, 384000 }; static struct snd_pcm_hw_constraint_list constraints_sample_rates = { @@ -321,6 +323,10 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) pr_debug("%s: perf: %x\n", __func__, prtd->audio_client->perf_mode); switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S32_LE: + bits_per_sample = 32; + sample_word_size = 32; + break; case SNDRV_PCM_FORMAT_S24_LE: bits_per_sample = 24; sample_word_size = 32; @@ -336,7 +342,7 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) break; } - ret = q6asm_open_write_v3(prtd->audio_client, + ret = q6asm_open_write_v4(prtd->audio_client, FORMAT_LINEAR_PCM, bits_per_sample); if (ret < 0) { @@ -361,11 +367,12 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) return ret; } - ret = q6asm_media_format_block_multi_ch_pcm_v3( + ret = q6asm_media_format_block_multi_ch_pcm_v4( prtd->audio_client, runtime->rate, runtime->channels, !prtd->set_channel_map, prtd->channel_map, bits_per_sample, - sample_word_size); + sample_word_size, ASM_LITTLE_ENDIAN, + DEFAULT_QF); if (ret < 0) pr_info("%s: CMD Format block failed\n", __func__); @@ -410,6 +417,8 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) if ((params_format(params) == SNDRV_PCM_FORMAT_S24_LE) || (params_format(params) == SNDRV_PCM_FORMAT_S24_3LE)) bits_per_sample = 24; + else if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE) + bits_per_sample = 32; /* ULL mode is not supported in capture path */ if (pdata->perf_mode_set == LEGACY_PCM_MODE) @@ -421,7 +430,7 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) __func__, params_channels(params), prtd->audio_client->perf_mode); - ret = q6asm_open_read_v3(prtd->audio_client, FORMAT_LINEAR_PCM, + ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, bits_per_sample); if (ret < 0) { pr_err("%s: q6asm_open_read failed\n", __func__); @@ -467,6 +476,10 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) return 0; switch (runtime->format) { + case SNDRV_PCM_FORMAT_S32_LE: + bits_per_sample = 32; + sample_word_size = 32; + break; case SNDRV_PCM_FORMAT_S24_LE: bits_per_sample = 24; sample_word_size = 32; @@ -485,11 +498,13 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n", __func__, prtd->samp_rate, prtd->channel_mode, bits_per_sample, sample_word_size); - ret = q6asm_enc_cfg_blk_pcm_format_support_v3(prtd->audio_client, + ret = q6asm_enc_cfg_blk_pcm_format_support_v4(prtd->audio_client, prtd->samp_rate, prtd->channel_mode, bits_per_sample, - sample_word_size); + sample_word_size, + ASM_LITTLE_ENDIAN, + DEFAULT_QF); if (ret < 0) pr_debug("%s: cmd cfg pcm was block failed", __func__); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h index 187133b1db75..a5df7f4f5281 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -59,11 +59,11 @@ struct msm_audio_in_frame_info { #define PLAYBACK_MIN_NUM_PERIODS 2 #define PLAYBACK_MAX_NUM_PERIODS 8 -#define PLAYBACK_MAX_PERIOD_SIZE 61440 +#define PLAYBACK_MAX_PERIOD_SIZE 122880 #define PLAYBACK_MIN_PERIOD_SIZE 128 #define CAPTURE_MIN_NUM_PERIODS 2 #define CAPTURE_MAX_NUM_PERIODS 8 -#define CAPTURE_MAX_PERIOD_SIZE 61440 +#define CAPTURE_MAX_PERIOD_SIZE 122880 #define CAPTURE_MIN_PERIOD_SIZE 320 struct msm_audio { From 5c1627b0dc147518d2e412a4283401b11cdeb88d Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Mon, 30 Oct 2017 14:53:22 +0530 Subject: [PATCH 033/392] ASoC: msm: qdsp6v2: add 32bit capture support in dai driver Add support for 24/32 bit recording support in FE and BE drivers. CRs-Fixed: 2129947 Change-Id: I22c0a98b1d6b724762de70c683672ddeaf76eb1e Signed-off-by: Surendar karka --- sound/soc/msm/msm-dai-fe.c | 36 ++++++++---- sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c | 64 ++++++++++++++++------ sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 3 + 3 files changed, 74 insertions(+), 29 deletions(-) diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c index 7857813ca3b0..b8f666d0ce15 100644 --- a/sound/soc/msm/msm-dai-fe.c +++ b/sound/soc/msm/msm-dai-fe.c @@ -108,7 +108,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -140,7 +141,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -223,7 +225,9 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .rates = (SNDRV_PCM_RATE_8000_192000| SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE), + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -255,7 +259,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .channels_min = 0, .channels_max = 8, .rate_min = 8000, @@ -288,7 +293,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -320,7 +326,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -372,7 +379,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -2118,7 +2126,10 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .aif_name = "MM_UL9", .rates = (SNDRV_PCM_RATE_8000_48000| SNDRV_PCM_RATE_KNOT), - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -2513,7 +2524,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -2532,7 +2544,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -2551,7 +2564,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { SNDRV_PCM_RATE_KNOT), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .channels_min = 1, .channels_max = 8, .rate_min = 8000, diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 80b03f9a02aa..f7482cafe7d6 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -3127,6 +3127,10 @@ static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_substream *substream, dai_data->port_config.i2s.bit_width = 24; dai_data->bitwidth = 24; break; + case SNDRV_PCM_FORMAT_S32_LE: + dai_data->port_config.i2s.bit_width = 32; + dai_data->bitwidth = 32; + break; default: pr_err("%s: format %d\n", __func__, params_format(params)); @@ -3285,10 +3289,14 @@ static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = { .stream_name = "Primary MI2S Capture", .aif_name = "PRI_MI2S_TX", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .ops = &msm_dai_q6_mi2s_ops, .id = MSM_PRIM_MI2S, @@ -3310,10 +3318,14 @@ static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = { .stream_name = "Secondary MI2S Capture", .aif_name = "SEC_MI2S_TX", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .ops = &msm_dai_q6_mi2s_ops, .id = MSM_SEC_MI2S, @@ -3334,10 +3346,14 @@ static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = { .stream_name = "Tertiary MI2S Capture", .aif_name = "TERT_MI2S_TX", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .ops = &msm_dai_q6_mi2s_ops, .id = MSM_TERT_MI2S, @@ -3359,10 +3375,14 @@ static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = { .stream_name = "Quaternary MI2S Capture", .aif_name = "QUAT_MI2S_TX", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .ops = &msm_dai_q6_mi2s_ops, .id = MSM_QUAT_MI2S, @@ -3396,10 +3416,14 @@ static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = { .stream_name = "Quinary MI2S Capture", .aif_name = "QUIN_MI2S_TX", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .ops = &msm_dai_q6_mi2s_ops, .id = MSM_QUIN_MI2S, @@ -3411,10 +3435,14 @@ static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = { .stream_name = "Senary_mi2s Capture", .aif_name = "SENARY_TX", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE), .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .ops = &msm_dai_q6_mi2s_ops, .id = MSM_SENARY_MI2S, diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 3b280cebe1ff..29c8d4632889 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -123,6 +123,9 @@ static int msm_routing_get_bit_width(unsigned int format) int bit_width; switch (format) { + case SNDRV_PCM_FORMAT_S32_LE: + bit_width = 32; + break; case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S24_3LE: bit_width = 24; From 3774a1b8642ade4ff2fe37c18c311276f8b1bcb9 Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Mon, 30 Oct 2017 14:40:13 +0530 Subject: [PATCH 034/392] ASoC: msm: add machine driver support for 32 bit recording Add support for 32 bit format support and configure the clock values based on format for capture stream. CRs-Fixed: 2129947 Change-Id: Ica513f61ea9cdbedb86b8c1d5997abc41c1acd1d Signed-off-by: Surendar karka --- sound/soc/msm/msm8952.c | 85 +++++++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 11 deletions(-) diff --git a/sound/soc/msm/msm8952.c b/sound/soc/msm/msm8952.c index 880677fc39a9..24fc90036b51 100644 --- a/sound/soc/msm/msm8952.c +++ b/sound/soc/msm/msm8952.c @@ -68,6 +68,9 @@ static int msm_vi_feed_tx_ch = 2; static int mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int mi2s_rx_bits_per_sample = 16; static int mi2s_rx_sample_rate = SAMPLING_RATE_48KHZ; +static int mi2s_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int mi2s_tx_bits_per_sample = 16; +static int mi2s_tx_sample_rate = SAMPLING_RATE_48KHZ; static atomic_t quat_mi2s_clk_ref; static atomic_t quin_mi2s_clk_ref; @@ -161,7 +164,8 @@ static struct afe_clk_set wsa_ana_clk = { 0, }; -static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; +static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE", + "S32_LE"}; static const char *const mi2s_ch_text[] = {"One", "Two"}; static const char *const loopback_mclk_text[] = {"DISABLE", "ENABLE"}; static const char *const btsco_rate_text[] = {"BTSCO_RATE_8KHZ", @@ -389,7 +393,7 @@ static int msm_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, pr_debug("%s(), channel:%d\n", __func__, msm_ter_mi2s_tx_ch); param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - SNDRV_PCM_FORMAT_S16_LE); + mi2s_tx_bit_format); rate->min = rate->max = 48000; channels->min = channels->max = msm_ter_mi2s_tx_ch; @@ -480,7 +484,7 @@ static int msm_mi2s_snd_hw_params(struct snd_pcm_substream *substream, mi2s_rx_bit_format); else param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - SNDRV_PCM_FORMAT_S16_LE); + mi2s_tx_bit_format); return 0; } @@ -549,7 +553,7 @@ static bool is_mi2s_rx_port(int port_id) return ret; } -static uint32_t get_mi2s_rx_clk_val(int port_id) +static uint32_t get_mi2s_clk_val(int port_id) { uint32_t clk_val = 0; @@ -559,8 +563,10 @@ static uint32_t get_mi2s_rx_clk_val(int port_id) */ if (is_mi2s_rx_port(port_id)) clk_val = (mi2s_rx_sample_rate * mi2s_rx_bits_per_sample * 2); + else + clk_val = (mi2s_tx_sample_rate * mi2s_tx_bits_per_sample * 2); - pr_debug("%s: MI2S Rx bit clock value: 0x%0x\n", __func__, clk_val); + pr_debug("%s: MI2S bit clock value: 0x%0x\n", __func__, clk_val); return clk_val; } @@ -581,7 +587,7 @@ static int msm_mi2s_sclk_ctl(struct snd_pcm_substream *substream, bool enable) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (pdata->afe_clk_ver == AFE_CLK_VERSION_V1) { mi2s_rx_clk_v1.clk_val1 = - get_mi2s_rx_clk_val(port_id); + get_mi2s_clk_val(port_id); ret = afe_set_lpass_clock(port_id, &mi2s_rx_clk_v1); } else { @@ -589,14 +595,14 @@ static int msm_mi2s_sclk_ctl(struct snd_pcm_substream *substream, bool enable) mi2s_rx_clk.clk_id = msm8952_get_clk_id(port_id); mi2s_rx_clk.clk_freq_in_hz = - get_mi2s_rx_clk_val(port_id); + get_mi2s_clk_val(port_id); ret = afe_set_lpass_clock_v2(port_id, &mi2s_rx_clk); } } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { if (pdata->afe_clk_ver == AFE_CLK_VERSION_V1) { mi2s_tx_clk_v1.clk_val1 = - Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; + get_mi2s_clk_val(port_id); ret = afe_set_lpass_clock(port_id, &mi2s_tx_clk_v1); } else { @@ -604,7 +610,7 @@ static int msm_mi2s_sclk_ctl(struct snd_pcm_substream *substream, bool enable) mi2s_tx_clk.clk_id = msm8952_get_clk_id(port_id); mi2s_tx_clk.clk_freq_in_hz = - Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; + get_mi2s_clk_val(port_id); ret = afe_set_lpass_clock_v2(port_id, &mi2s_tx_clk); } @@ -790,6 +796,61 @@ static int mi2s_rx_bit_format_put(struct snd_kcontrol *kcontrol, return 0; } +static int mi2s_tx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 3: + mi2s_tx_bit_format = SNDRV_PCM_FORMAT_S32_LE; + mi2s_tx_bits_per_sample = 32; + break; + case 2: + mi2s_tx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + mi2s_tx_bits_per_sample = 32; + break; + case 1: + mi2s_tx_bit_format = SNDRV_PCM_FORMAT_S24_LE; + mi2s_tx_bits_per_sample = 32; + break; + case 0: + default: + mi2s_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE; + mi2s_tx_bits_per_sample = 16; + break; + } + return 0; +} + +static int mi2s_tx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + switch (mi2s_tx_bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: mi2s_tx_bit_format = %d, ucontrol value = %ld\n", + __func__, mi2s_tx_bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + static int loopback_mclk_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -988,8 +1049,8 @@ static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol, } static const struct soc_enum msm_snd_enum[] = { - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_bit_format_text), - rx_bit_format_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(bit_format_text), + bit_format_text), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mi2s_ch_text), mi2s_ch_text), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(loopback_mclk_text), @@ -1007,6 +1068,8 @@ static const struct soc_enum msm_snd_enum[] = { static const struct snd_kcontrol_new msm_snd_controls[] = { SOC_ENUM_EXT("MI2S_RX Format", msm_snd_enum[0], mi2s_rx_bit_format_get, mi2s_rx_bit_format_put), + SOC_ENUM_EXT("MI2S_TX Format", msm_snd_enum[0], + mi2s_tx_bit_format_get, mi2s_tx_bit_format_put), SOC_ENUM_EXT("MI2S_TX Channels", msm_snd_enum[1], msm_ter_mi2s_tx_ch_get, msm_ter_mi2s_tx_ch_put), SOC_ENUM_EXT("MI2S_RX Channels", msm_snd_enum[1], From 8b64d42337b98a482b09ad9112edb3d9f3e5eaf9 Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Mon, 30 Oct 2017 14:39:27 +0530 Subject: [PATCH 035/392] ASoC: codecs: add 32bit capture support in codec Add 32 bit format support and set I2S mode based on format in Tx path. CRs-Fixed: 2129947 Change-Id: I017bc8764368cc20ce691598d793167641a48e7f Signed-off-by: Surendar karka --- sound/soc/codecs/msm8x16-wcd.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index 43b50fa4a8c3..b047b499c8d3 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -49,7 +49,8 @@ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000) #define MSM8X16_WCD_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE |\ - SNDRV_PCM_FMTBIT_S24_3LE) + SNDRV_PCM_FMTBIT_S24_3LE |\ + SNDRV_PCM_FMTBIT_S32_LE) #define NUM_INTERPOLATORS 3 #define BITS_PER_REG 8 @@ -4749,13 +4750,24 @@ static int msm8x16_wcd_hw_params(struct snd_pcm_substream *substream, } switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: - snd_soc_update_bits(dai->codec, + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + snd_soc_update_bits(dai->codec, MSM8X16_WCD_A_CDC_CLK_RX_I2S_CTL, 0x20, 0x20); + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + snd_soc_update_bits(dai->codec, + MSM8X16_WCD_A_CDC_CLK_TX_I2S_CTL, 0x20, 0x20); + } break; case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S24_3LE: - snd_soc_update_bits(dai->codec, + case SNDRV_PCM_FORMAT_S32_LE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + snd_soc_update_bits(dai->codec, MSM8X16_WCD_A_CDC_CLK_RX_I2S_CTL, 0x20, 0x00); + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + snd_soc_update_bits(dai->codec, + MSM8X16_WCD_A_CDC_CLK_TX_I2S_CTL, 0x20, 0x00); + } break; default: dev_err(dai->codec->dev, "%s: wrong format selected\n", From e10d98fd1f835dc635030e7cf6b7298351aa33ac Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Wed, 22 Nov 2017 17:40:28 +0530 Subject: [PATCH 036/392] ASoC: msm: add afe loopback support for apq8009 Add machine driver changes for AFE Rx to Tx loopback. CRs-Fixed: 2147850 Change-Id: I725c7de21172516598edc30ac7aa9b5b43ee6f56 Signed-off-by: Surendar karka Signed-off-by: Dhanalakshmi Siddani --- sound/soc/msm/apq8009-i2s-ext-codec.c | 36 +++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/sound/soc/msm/apq8009-i2s-ext-codec.c b/sound/soc/msm/apq8009-i2s-ext-codec.c index 22abdac808d8..896c7fd8448f 100644 --- a/sound/soc/msm/apq8009-i2s-ext-codec.c +++ b/sound/soc/msm/apq8009-i2s-ext-codec.c @@ -1070,6 +1070,22 @@ static struct snd_soc_ops msm_pri_auxpcm_be_ops = { .startup = msm_prim_auxpcm_startup, }; +static struct snd_soc_dai_link msm_afe_rxtx_lb_be_dai_link[] = { + { + .name = LPASS_BE_AFE_LOOPBACK_TX, + .stream_name = "AFE Loopback Capture", + .cpu_dai_name = "msm-dai-q6-dev.24577", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_AFE_LOOPBACK_TX, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link apq8009_9326_dai[] = { /* Backend DAI Links */ { @@ -1740,7 +1756,8 @@ static struct snd_soc_dai_link apq8009_dai[] = { static struct snd_soc_dai_link apq8009_9326_dai_links[ ARRAY_SIZE(apq8009_dai) + - ARRAY_SIZE(apq8009_9326_dai)]; + ARRAY_SIZE(apq8009_9326_dai) + + ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link)]; static struct snd_soc_card snd_soc_card_9326_apq8009; @@ -1760,7 +1777,7 @@ static int populate_ext_snd_card_dt_data(struct platform_device *pdev) struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) { struct snd_soc_card *card = &snd_soc_card_9326_apq8009; - int num_links, ret; + int ret, len1, len2; card->dev = dev; ret = snd_soc_of_parse_card_name(card, "qcom,model"); @@ -1771,16 +1788,25 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) } pr_debug("%s: CARD is %s\n", __func__, card->name); - num_links = ARRAY_SIZE(apq8009_9326_dai_links); + len1 = ARRAY_SIZE(apq8009_dai); + len2 = len1 + ARRAY_SIZE(apq8009_9326_dai); memcpy(apq8009_9326_dai_links, apq8009_dai, sizeof(apq8009_dai)); - memcpy(apq8009_9326_dai_links + ARRAY_SIZE(apq8009_dai), + memcpy(apq8009_9326_dai_links + len1, apq8009_9326_dai, sizeof(apq8009_9326_dai)); + if (of_property_read_bool(dev->of_node, "qcom,afe-rxtx-lb")) { + dev_dbg(dev, "%s(): AFE RX to TX loopback supported\n", + __func__); + memcpy(apq8009_9326_dai_links + len2, + msm_afe_rxtx_lb_be_dai_link, + sizeof(msm_afe_rxtx_lb_be_dai_link)); + len2 += ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link); + } card->dai_link = apq8009_9326_dai_links; - card->num_links = num_links; + card->num_links = len2; card->dev = dev; return card; From e84739d11523439a87f79141a7381758fcc24562 Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Wed, 22 Nov 2017 18:09:54 +0530 Subject: [PATCH 037/392] ASoC: msm: add tdm support in machine driver for apq8009 Add dai_links and soc_ops to support TDM in apq8009. CRs-Fixed: 2147847 Change-Id: Ic47c3f36665e1d61a1ee0140634262f78bcd2025 Signed-off-by: Surendar karka --- sound/soc/msm/apq8009-i2s-ext-codec.c | 680 +++++++++++++++++++++++++- 1 file changed, 672 insertions(+), 8 deletions(-) diff --git a/sound/soc/msm/apq8009-i2s-ext-codec.c b/sound/soc/msm/apq8009-i2s-ext-codec.c index 896c7fd8448f..b6790e2682a9 100644 --- a/sound/soc/msm/apq8009-i2s-ext-codec.c +++ b/sound/soc/msm/apq8009-i2s-ext-codec.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -69,11 +70,48 @@ #define WSA8810_NAME_1 "wsa881x.20170211" #define WSA8810_NAME_2 "wsa881x.20170212" +#define TDM_SLOT_OFFSET_MAX 8 + enum btsco_rates { RATE_8KHZ_ID, RATE_16KHZ_ID, }; +enum { + PRIMARY_TDM_RX_0, + PRIMARY_TDM_TX_0, + SECONDARY_TDM_RX_0, + SECONDARY_TDM_TX_0, + TDM_MAX, +}; + + +/* TDM default channels */ +static int msm_pri_tdm_rx_0_ch = 8; +static int msm_pri_tdm_tx_0_ch = 8; + +/* TDM default bit format */ +static int msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; +static int msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; + +/* TDM default sampling rate */ +static int msm_pri_tdm_rx_0_sample_rate = SAMPLING_RATE_48KHZ; +static int msm_pri_tdm_tx_0_sample_rate = SAMPLING_RATE_48KHZ; + +static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", "Eight"}; +static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE", + "S32_LE"}; +static char const *tdm_sample_rate_text[] = {"KHZ_16", "KHZ_48"}; + +/* TDM default offset */ +static unsigned int tdm_slot_offset[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { + /* PRI_TDM_RX */ + {0, 4, 8, 12, 16, 20, 24, 28}, + /* PRI_TDM_TX */ + {0, 4, 8, 12, 16, 20, 24, 28}, +}; + struct apq8009_asoc_mach_data { int mclk_freq; struct afe_digital_clk_cfg digital_cdc_clk; @@ -292,6 +330,203 @@ static char const *pri_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", "KHZ_192", "KHZ_8", "KHZ_16", "KHZ_32"}; + +static int msm_pri_tdm_rx_0_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("msm_pri_tdm_rx_0_ch = %d", + msm_pri_tdm_rx_0_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_rx_0_ch - 1; + return 0; +} + +static int msm_pri_tdm_rx_0_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_rx_0_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("msm_pri_tdm_rx_0_ch = %d", + msm_pri_tdm_rx_0_ch); + return 0; +} + +static int msm_pri_tdm_tx_0_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("msm_pri_tdm_tx_0_ch = %d", + msm_pri_tdm_tx_0_ch); + ucontrol->value.integer.value[0] = msm_pri_tdm_tx_0_ch - 1; + return 0; +} + +static int msm_pri_tdm_tx_0_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_pri_tdm_tx_0_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("msm_pri_tdm_tx_0_ch = %d", + msm_pri_tdm_tx_0_ch); + return 0; +} + +static int msm_pri_tdm_rx_0_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_rx_0_bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("msm_pri_tdm_rx_0_bit_format = %ld", + ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_rx_0_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 3: + msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("msm_pri_tdm_rx_0_bit_format = %d", + msm_pri_tdm_rx_0_bit_format); + return 0; +} + +static int msm_pri_tdm_tx_0_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_tx_0_bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("msm_pri_tdm_tx_0_bit_format = %ld", + ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_tx_0_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 3: + msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("msm_pri_tdm_tx_0_bit_format = %d", + msm_pri_tdm_tx_0_bit_format); + return 0; +} + +static int msm_pri_tdm_rx_0_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_rx_0_sample_rate) { + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 0; + break; + case SAMPLING_RATE_48KHZ: + default: + ucontrol->value.integer.value[0] = 1; + break; + } + pr_debug("msm_pri_tdm_rx_0_sample_rate = %ld", + ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_rx_0_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 0: + msm_pri_tdm_rx_0_sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + default: + msm_pri_tdm_rx_0_sample_rate = SAMPLING_RATE_48KHZ; + break; + } + pr_debug("msm_pri_tdm_rx_0_sample_rate = %d", + msm_pri_tdm_rx_0_sample_rate); + return 0; +} + +static int msm_pri_tdm_tx_0_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (msm_pri_tdm_tx_0_sample_rate) { + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 0; + break; + case SAMPLING_RATE_48KHZ: + default: + ucontrol->value.integer.value[0] = 1; + break; + } + pr_debug("msm_pri_tdm_tx_0_sample_rate = %ld", + ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_pri_tdm_tx_0_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 0: + msm_pri_tdm_tx_0_sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + default: + msm_pri_tdm_tx_0_sample_rate = SAMPLING_RATE_48KHZ; + break; + } + pr_debug("msm_pri_tdm_tx_0_sample_rate = %d", + msm_pri_tdm_tx_0_sample_rate); + return 0; +} + static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -502,6 +737,203 @@ static int msm_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } + +static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + channels->min = channels->max = msm_pri_tdm_rx_0_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_rx_0_bit_format); + rate->min = rate->max = msm_pri_tdm_rx_0_sample_rate; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX: + channels->min = channels->max = msm_pri_tdm_tx_0_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + msm_pri_tdm_tx_0_bit_format); + rate->min = rate->max = msm_pri_tdm_tx_0_sample_rate; + break; + default: + pr_err("%s: dai id 0x%x not supported", __func__, + cpu_dai->id); + return -EINVAL; + } + + pr_debug("%s: dai id = 0x%x channels = %d rate = %d", __func__, + cpu_dai->id, channels->max, rate->max); + + return 0; +} + +static unsigned int tdm_param_set_slot_mask(u16 port_id, + int slot_width, int channels) +{ + unsigned int slot_mask = 0; + int upper, lower, i, j; + unsigned int *slot_offset; + + switch (port_id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + lower = PRIMARY_TDM_RX_0; + upper = PRIMARY_TDM_RX_0; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX: + lower = PRIMARY_TDM_TX_0; + upper = PRIMARY_TDM_TX_0; + break; + default: + return slot_mask; + } + + for (i = lower; i <= upper; i++) { + slot_offset = tdm_slot_offset[i]; + for (j = 0; j < channels; j++) { + if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID) + /* + * set the mask of active slot according to + * the offset table for the group of devices + */ + slot_mask |= + (1 << ((slot_offset[j] * 8) / slot_width)); + else + break; + } + } + + return slot_mask; +} + +static int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + int channels, slot_width, slots; + unsigned int slot_mask; + unsigned int *slot_offset; + int offset_channels = 0; + int i; + + pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id); + + channels = params_channels(params); + switch (channels) { + case 1: + case 2: + case 3: + case 4: + case 6: + case 8: + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S16_LE: + /* + * up to 8 channel HW configuration should + * use 32 bit slot width for max support of + * stream bit width. (slot_width > bit_width) + */ + slot_width = 32; + break; + default: + pr_err("%s: invalid param format 0x%x\n", + __func__, params_format(params)); + return -EINVAL; + } + slots = 8; + slot_mask = tdm_param_set_slot_mask(cpu_dai->id, + slot_width, channels); + if (!slot_mask) { + pr_err("%s: invalid slot_mask 0x%x\n", + __func__, slot_mask); + return -EINVAL; + } + break; + default: + pr_err("%s: invalid param channels %d\n", + __func__, channels); + return -EINVAL; + } + + switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_0]; + break; + case AFE_PORT_ID_PRIMARY_TDM_TX: + slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_0]; + break; + default: + pr_err("%s: dai id 0x%x not supported\n", + __func__, cpu_dai->id); + return -EINVAL; + } + + for (i = 0; i < channels; i++) { + if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID) + offset_channels++; + else + break; + } + + if (offset_channels == 0) { + pr_err("%s: slot offset not supported, offset_channels %d\n", + __func__, offset_channels); + return -EINVAL; + } + + if (channels > offset_channels) { + pr_err("%s: channels %d exceed offset_channels %d\n", + __func__, channels, offset_channels); + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask, + slots, slot_width); + if (ret < 0) { + pr_err("%s: failed to set tdm slot, err:%d\n", + __func__, ret); + goto end; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, + 0, NULL, channels, slot_offset); + if (ret < 0) { + pr_err("%s: failed to set channel map, err:%d\n", + __func__, ret); + goto end; + } + } else { + ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0, + slots, slot_width); + if (ret < 0) { + pr_err("%s: failed to set tdm slot, err:%d\n", + __func__, ret); + goto end; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, + channels, slot_offset, 0, NULL); + if (ret < 0) { + pr_err("%s: failed to set channel map, err:%d\n", + __func__, ret); + goto end; + } + } + +end: + return ret; +} + static int msm_pri_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -779,6 +1211,12 @@ static const struct soc_enum msm_snd_enum[] = { SOC_ENUM_SINGLE_EXT(3, rx_bit_format_text), SOC_ENUM_SINGLE_EXT(4, mi2s_tx_ch_text), SOC_ENUM_SINGLE_EXT(6, pri_rx_sample_rate_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_ch_text), + tdm_ch_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_bit_format_text), + tdm_bit_format_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_sample_rate_text), + tdm_sample_rate_text), }; static const char *const btsco_rate_text[] = {"BTSCO_RATE_8KHZ", @@ -800,6 +1238,22 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_btsco_rate_get, msm_btsco_rate_put), SOC_ENUM_EXT("MI2S_RX SampleRate", msm_snd_enum[2], pri_rx_sample_rate_get, pri_rx_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", msm_snd_enum[3], + msm_pri_tdm_rx_0_ch_get, msm_pri_tdm_rx_0_ch_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", msm_snd_enum[3], + msm_pri_tdm_tx_0_ch_get, msm_pri_tdm_tx_0_ch_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Bit Format", msm_snd_enum[4], + msm_pri_tdm_rx_0_bit_format_get, + msm_pri_tdm_rx_0_bit_format_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Bit Format", msm_snd_enum[4], + msm_pri_tdm_tx_0_bit_format_get, + msm_pri_tdm_tx_0_bit_format_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", msm_snd_enum[5], + msm_pri_tdm_rx_0_sample_rate_get, + msm_pri_tdm_rx_0_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 SampleRate", msm_snd_enum[5], + msm_pri_tdm_tx_0_sample_rate_get, + msm_pri_tdm_tx_0_sample_rate_put), }; static int apq8009_mclk_event(struct snd_soc_dapm_widget *w, @@ -974,6 +1428,101 @@ static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream) __func__, "pri_i2s"); } + +static int msm_tdm_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct apq8009_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0, val = 0; + + pr_debug("substream = %s stream = %d", + substream->name, substream->stream); + pr_debug("dai id = 0x%x", cpu_dai->id); + + switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + case AFE_PORT_ID_PRIMARY_TDM_RX_1: + case AFE_PORT_ID_PRIMARY_TDM_RX_2: + case AFE_PORT_ID_PRIMARY_TDM_RX_3: + case AFE_PORT_ID_PRIMARY_TDM_RX_4: + case AFE_PORT_ID_PRIMARY_TDM_RX_5: + case AFE_PORT_ID_PRIMARY_TDM_RX_6: + case AFE_PORT_ID_PRIMARY_TDM_RX_7: + case AFE_PORT_ID_PRIMARY_TDM_TX: + case AFE_PORT_ID_PRIMARY_TDM_TX_1: + case AFE_PORT_ID_PRIMARY_TDM_TX_2: + case AFE_PORT_ID_PRIMARY_TDM_TX_3: + case AFE_PORT_ID_PRIMARY_TDM_TX_4: + case AFE_PORT_ID_PRIMARY_TDM_TX_5: + case AFE_PORT_ID_PRIMARY_TDM_TX_6: + case AFE_PORT_ID_PRIMARY_TDM_TX_7: + /* Configure mux for Primary TDM */ + if (pdata->vaddr_gpio_mux_pcm_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_pcm_ctl); + val = val | 0x00000001; + iowrite32(val, pdata->vaddr_gpio_mux_pcm_ctl); + } else { + return -EINVAL; + } + if (pdata->vaddr_gpio_mux_mic_ctl) { + val = ioread32(pdata->vaddr_gpio_mux_mic_ctl); + /*0x1808000 Use this value for slave mode*/ + val = val | 0x02020002; /*this is for master mode*/ + iowrite32(val, pdata->vaddr_gpio_mux_mic_ctl); + } else { + return -EINVAL; + } + + ret = msm_gpioset_activate(CLIENT_WCD_EXT, "quat_i2s"); + if (ret < 0) + pr_err("%s: failed to activate primary TDM gpio set\n", + __func__); + break; + default: + pr_err("dai id 0x%x not supported", cpu_dai->id); + break; + return -EINVAL; + } + return ret; +} + +static void msm_tdm_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + + switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + case AFE_PORT_ID_PRIMARY_TDM_RX_1: + case AFE_PORT_ID_PRIMARY_TDM_RX_2: + case AFE_PORT_ID_PRIMARY_TDM_RX_3: + case AFE_PORT_ID_PRIMARY_TDM_RX_4: + case AFE_PORT_ID_PRIMARY_TDM_RX_5: + case AFE_PORT_ID_PRIMARY_TDM_RX_6: + case AFE_PORT_ID_PRIMARY_TDM_RX_7: + case AFE_PORT_ID_PRIMARY_TDM_TX: + case AFE_PORT_ID_PRIMARY_TDM_TX_1: + case AFE_PORT_ID_PRIMARY_TDM_TX_2: + case AFE_PORT_ID_PRIMARY_TDM_TX_3: + case AFE_PORT_ID_PRIMARY_TDM_TX_4: + case AFE_PORT_ID_PRIMARY_TDM_TX_5: + case AFE_PORT_ID_PRIMARY_TDM_TX_6: + ret = msm_gpioset_suspend(CLIENT_WCD_EXT, "quat_i2s"); + if (ret < 0) { + pr_err("%s: gpio set cannot be de-activated %s\n", + __func__, "pri_tdm"); + return; + } + break; + default: + break; + } +} + static int msm_audrx_init_wcd(struct snd_soc_pcm_runtime *rtd) { @@ -1086,6 +1635,12 @@ static struct snd_soc_dai_link msm_afe_rxtx_lb_be_dai_link[] = { }, }; +static struct snd_soc_ops msm_tdm_be_ops = { + .startup = msm_tdm_startup, + .hw_params = msm_tdm_snd_hw_params, + .shutdown = msm_tdm_shutdown, +}; + static struct snd_soc_dai_link apq8009_9326_dai[] = { /* Backend DAI Links */ { @@ -1754,10 +2309,108 @@ static struct snd_soc_dai_link apq8009_dai[] = { }, }; +static struct snd_soc_dai_link msm_tdm_fe_dai[] = { + /* FE TDM DAI links */ + { + .name = "Primary TDM RX 0 Hostless", + .stream_name = "Primary TDM RX 0 Hostless", + .cpu_dai_name = "PRI_TDM_RX_0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Primary TDM TX 0 Hostless", + .stream_name = "Primary TDM TX 0 Hostless", + .cpu_dai_name = "PRI_TDM_TX_0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Secondary TDM RX 0 Hostless", + .stream_name = "Secondary TDM RX 0 Hostless", + .cpu_dai_name = "SEC_TDM_RX_0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Secondary TDM TX 0 Hostless", + .stream_name = "Secondary TDM TX 0 Hostless", + .cpu_dai_name = "SEC_TDM_TX_0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, +}; + +static struct snd_soc_dai_link msm_tdm_be_dai[] = { + /* TDM be dai links */ + { + .name = LPASS_BE_PRI_TDM_RX_0, + .stream_name = "Primary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36864", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_0, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_TX_0, + .stream_name = "Primary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36865", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_0, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link apq8009_9326_dai_links[ ARRAY_SIZE(apq8009_dai) + + ARRAY_SIZE(msm_tdm_fe_dai) + ARRAY_SIZE(apq8009_9326_dai) + - ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link)]; + ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link) + + ARRAY_SIZE(msm_tdm_be_dai)]; static struct snd_soc_card snd_soc_card_9326_apq8009; @@ -1777,7 +2430,7 @@ static int populate_ext_snd_card_dt_data(struct platform_device *pdev) struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) { struct snd_soc_card *card = &snd_soc_card_9326_apq8009; - int ret, len1, len2; + int ret, len1, len2, len3; card->dev = dev; ret = snd_soc_of_parse_card_name(card, "qcom,model"); @@ -1789,24 +2442,35 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) pr_debug("%s: CARD is %s\n", __func__, card->name); len1 = ARRAY_SIZE(apq8009_dai); - len2 = len1 + ARRAY_SIZE(apq8009_9326_dai); + len2 = len1 + ARRAY_SIZE(msm_tdm_fe_dai); + len3 = len2 + ARRAY_SIZE(apq8009_9326_dai); memcpy(apq8009_9326_dai_links, apq8009_dai, sizeof(apq8009_dai)); - memcpy(apq8009_9326_dai_links + len1, - apq8009_9326_dai, sizeof(apq8009_9326_dai)); + memcpy(apq8009_9326_dai_links + len1, msm_tdm_fe_dai, + sizeof(msm_tdm_fe_dai)); + memcpy(apq8009_9326_dai_links + len2, apq8009_9326_dai, + sizeof(apq8009_9326_dai)); if (of_property_read_bool(dev->of_node, "qcom,afe-rxtx-lb")) { dev_dbg(dev, "%s(): AFE RX to TX loopback supported\n", __func__); - memcpy(apq8009_9326_dai_links + len2, + memcpy(apq8009_9326_dai_links + len3, msm_afe_rxtx_lb_be_dai_link, sizeof(msm_afe_rxtx_lb_be_dai_link)); - len2 += ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link); + len3 += ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link); + } + + if (of_property_read_bool(dev->of_node, "qcom,tdm-audio-intf")) { + dev_dbg(dev, "%s(): TDM support present\n", + __func__); + memcpy(apq8009_9326_dai_links + len3, msm_tdm_be_dai, + sizeof(msm_tdm_be_dai)); + len3 += ARRAY_SIZE(msm_tdm_be_dai); } card->dai_link = apq8009_9326_dai_links; - card->num_links = len2; + card->num_links = len3; card->dev = dev; return card; From eb5a7ca1f41a2b331f50346efd60ab155bb6ae77 Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Wed, 22 Nov 2017 17:59:02 +0530 Subject: [PATCH 038/392] ARM: dts: msm: add TDM support for apq8009 Add primary Tx/Rx dai property and cpu names to support TDM in apq8009. CRs-Fixed: 2147847 Change-Id: I2d9f8351fe3f2fee46ae7a7b75c94073b001b16b Signed-off-by: Surendar karka --- .../qcom/apq8009-audio-external_codec.dtsi | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi b/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi index 84589e813761..c70e5ec90cec 100644 --- a/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi +++ b/arch/arm/boot/dts/qcom/apq8009-audio-external_codec.dtsi @@ -27,6 +27,7 @@ qcom,msm-mbhc-gnd-swh = <0>; qcom,afe-rxtx-lb; qcom,msm-mclk-freq = <9600000>; + qcom,tdm-audio-intf; qcom,msm-hs-micbias-type = "internal"; qcom,audio-routing = "AIF4 VI", "MCLK", @@ -89,7 +90,8 @@ <&incall_music_rx>, <&incall_music_2_rx>, <&bt_sco_rx>, <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>, - <&afe_loopback_tx>; + <&afe_loopback_tx>, <&dai_pri_tdm_rx_0>, + <&dai_pri_tdm_tx_0>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", @@ -104,7 +106,8 @@ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293", - "msm-dai-q6-dev.24577"; + "msm-dai-q6-dev.24577", "msm-dai-q6-tdm.36864", + "msm-dai-q6-tdm.36865"; asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; qcom,wsa-max-devs = <2>; @@ -224,4 +227,44 @@ }; }; }; + + pri_tdm_rx: qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36864>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-sec-port-enable; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + pri_tdm_tx: qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36865>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-sec-port-enable; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; }; From e80187b43fb84571d6554327422f8f5ae186b67b Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Fri, 22 Sep 2017 18:19:36 +0530 Subject: [PATCH 039/392] ASoC: msm: qdsp6v2: Add TDM changes in dai driver Update dai driver with TDM dai related changes. Add a property to help not to configure the AFE EBIT on platforms where it is not supported. Change-Id: Ic10cbb58f31698ceb03a07d94c8834515e828a93 Signed-off-by: Yeleswarapu Nagaradhesh Signed-off-by: Ashish Jain --- .../bindings/sound/qcom-audio-dev.txt | 7 + sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c | 193 ++++++++++++++++-- 2 files changed, 182 insertions(+), 18 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 80c8fd14ef94..80eb3ed2b4e7 100755 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -1371,6 +1371,13 @@ Required properties: When clock rate is set to zero, then external clock is assumed. + - qcom,msm-cpudai-tdm-afe-ebit-unsupported: Notify if ebit setting is needed + When this is set , alongwith + clock rate as zero then afe + is not configured for clock. + + + [Second Level Nodes] Required properties: diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 80b03f9a02aa..4b1159d3774b 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -190,17 +190,22 @@ struct msm_dai_q6_auxpcm_dai_data { struct msm_dai_q6_dai_data bdai_data; /* incoporate base DAI data */ }; +static union afe_port_group_config group_cfg_tx; + struct msm_dai_q6_tdm_dai_data { DECLARE_BITMAP(status_mask, STATUS_MAX); u32 rate; u32 channels; u32 bitwidth; u32 num_group_ports; + bool afe_ebit_unsupported; struct afe_clk_set clk_set; /* hold LPASS clock config. */ union afe_port_group_config group_cfg; /* hold tdm group config */ struct afe_tdm_port_config port_cfg; /* hold tdm config */ }; +static bool afe_ebit_unsupported; + /* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command * 0: linear PCM * 1: non-linear PCM @@ -2049,7 +2054,7 @@ static struct snd_soc_dai_driver msm_dai_q6_afe_lb_tx_dai[] = { .channels_min = 1, .channels_max = 8, .rate_min = 8000, - .rate_max = 48000, + .rate_max = 48000, }, .id = AFE_LOOPBACK_TX, .probe = msm_dai_q6_dai_probe, @@ -4131,6 +4136,11 @@ static int msm_dai_tdm_q6_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: Clk Attribute from DT file %d\n", __func__, tdm_clk_set.clk_attri); + afe_ebit_unsupported = of_property_read_bool(pdev->dev.of_node, + "qcom,msm-cpudai-tdm-afe-ebit-unsupported"); + + dev_dbg(&pdev->dev, "afe_ebit_unsupported %d\n", afe_ebit_unsupported); + /* other initializations within device group */ atomic_set(&tdm_group_ref[group_idx], 0); @@ -4906,6 +4916,9 @@ static int msm_dai_q6_tdm_set_clk( { int rc = 0; + pr_debug("dai_data->group_cfg.tdm_cfg.group_id = %d : %d\n", + dai_data->group_cfg.tdm_cfg.group_id, + dai_data->clk_set.clk_freq_in_hz); switch (dai_data->group_cfg.tdm_cfg.group_id) { case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX: case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX: @@ -5118,6 +5131,10 @@ static int msm_dai_q6_tdm_set_tdm_slot(struct snd_soc_dai *dai, case 16: cap_mask = 0xFFFF; break; + case 4: + cap_mask = 0xF; + break; + default: dev_err(dai->dev, "%s: invalid slots %d\n", __func__, slots); @@ -5160,6 +5177,11 @@ static int msm_dai_q6_tdm_set_tdm_slot(struct snd_soc_dai *dai, tdm_group->nslots_per_frame = slots; tdm_group->slot_width = slot_width; tdm_group->slot_mask = rx_mask & cap_mask; + dev_dbg(dai->dev, "%s:Rx:tdm_group->nslots_per_frame %d\n" + "tdm_group->slot_width %d\n" + "tdm_group->slot_mask %d\n", __func__, + tdm_group->nslots_per_frame, + tdm_group->slot_width, tdm_group->slot_mask); break; case AFE_PORT_ID_PRIMARY_TDM_TX: case AFE_PORT_ID_PRIMARY_TDM_TX_1: @@ -5196,6 +5218,10 @@ static int msm_dai_q6_tdm_set_tdm_slot(struct snd_soc_dai *dai, tdm_group->nslots_per_frame = slots; tdm_group->slot_width = slot_width; tdm_group->slot_mask = tx_mask & cap_mask; + dev_dbg(dai->dev, "%s:Tx:tdm_group->nslots_per_frame %d\n" + "tdm_group->slot_width %d,tdm_group->slot_mask %d\n" + "tx%d\n", __func__, tdm_group->nslots_per_frame, + tdm_group->slot_width, tdm_group->slot_mask, tx_mask); break; default: dev_err(dai->dev, "%s: invalid dai id 0x%x\n", @@ -5497,6 +5523,23 @@ static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream, custom_tdm_header->header[7]); } + memcpy(&group_cfg_tx.group_cfg, &dai_data->group_cfg.group_cfg, + sizeof(dai_data->group_cfg.group_cfg)); + memcpy(&group_cfg_tx.group_enable, &dai_data->group_cfg.group_enable, + sizeof(dai_data->group_cfg.group_enable)); + memcpy(&group_cfg_tx.tdm_cfg, &dai_data->group_cfg.tdm_cfg, + sizeof(dai_data->group_cfg.tdm_cfg)); + pr_debug("%s: TDM GROUP:\n" + "num_channels=%d sample_rate=%d bit_width=%d\n" + "nslots_per_frame=%d slot_width=%d slot_mask=0x%x\n", + __func__, + group_cfg_tx.tdm_cfg.num_channels, + group_cfg_tx.tdm_cfg.sample_rate, + group_cfg_tx.tdm_cfg.bit_width, + group_cfg_tx.tdm_cfg.nslots_per_frame, + group_cfg_tx.tdm_cfg.slot_width, + group_cfg_tx.tdm_cfg.slot_mask); + return 0; } @@ -5508,6 +5551,8 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, dev_get_drvdata(dai->dev); u16 group_id = dai_data->group_cfg.tdm_cfg.group_id; int group_idx = 0; + u16 prim_port_id = 0; + u16 sec_port_id = 0; atomic_t *group_ref = NULL; group_idx = msm_dai_q6_get_group_idx(dai->id); @@ -5528,41 +5573,104 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, /* TX and RX share the same clk. AFE clk is enabled per group to simplify the logic. DSP will monitor the clk count. */ - rc = msm_dai_q6_tdm_set_clk(dai_data, - dai->id, true); - if (IS_ERR_VALUE(rc)) { - dev_err(dai->dev, "%s: fail to enable AFE clk 0x%x\n", - __func__, dai->id); - goto rtn; + if (!(dai_data->afe_ebit_unsupported && + !dai_data->clk_set.clk_freq_in_hz)) { + rc = msm_dai_q6_tdm_set_clk(dai_data, + dai->id, true); + if (IS_ERR_VALUE(rc)) { + dev_err(dai->dev, "%s: fail to enable AFE clk 0x%x\n", + __func__, dai->id); + goto rtn; + } } if (dai_data->num_group_ports > 1) { + dev_dbg(dai->dev, "%s:enable RX afe group\n", + __func__); rc = afe_port_group_enable(group_id, &dai_data->group_cfg, true); if (IS_ERR_VALUE(rc)) { - dev_err(dai->dev, "%s: fail to enable AFE group 0x%x\n", + dev_err(dai->dev, + "%s:failed to enable grp %x\n", __func__, group_id); goto rtn; } } } - - rc = afe_tdm_port_start(dai->id, &dai_data->port_cfg, + /* + * 8909 HW has a dependency where for Rx/Tx to work in TDM mode + * We need to start a Tx or Rx port in the same group. + * Hence for BG use TDM_TX when a RX session is requested and + * use TDM_RX port when a TX session is requested as these ports + * are unused as of now. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + prim_port_id = dai->id; + if (dai_data->afe_ebit_unsupported) + sec_port_id = AFE_PORT_ID_PRIMARY_TDM_TX; + } else { + prim_port_id = dai->id; + if (dai_data->afe_ebit_unsupported) + sec_port_id = AFE_PORT_ID_PRIMARY_TDM_RX; + } + dev_dbg(dai->dev, "\n%s:open prim port id %d TDM rate: %d\n" + "dai_data->port_cfg.tdm.slot_mask %x\n" + "dai_data->port_cfg.tdm.nslots_per_frame:%x\n", + __func__, prim_port_id, + dai_data->port_cfg.tdm.num_channels, + dai_data->port_cfg.tdm.slot_mask, + dai_data->port_cfg.tdm.nslots_per_frame); + + rc = afe_tdm_port_start(prim_port_id, &dai_data->port_cfg, dai_data->rate, dai_data->num_group_ports); + if (IS_ERR_VALUE(rc)) { if (atomic_read(group_ref) == 0) { afe_port_group_enable(group_id, NULL, false); - msm_dai_q6_tdm_set_clk(dai_data, - dai->id, false); + if (!(dai_data->afe_ebit_unsupported && + !dai_data->clk_set.clk_freq_in_hz)) + msm_dai_q6_tdm_set_clk(dai_data, + dai->id, false); } - dev_err(dai->dev, "%s: fail to open AFE port 0x%x\n", - __func__, dai->id); + dev_err(dai->dev, "%s: open AFE port 0x%x\n", + __func__, prim_port_id); } else { set_bit(STATUS_PORT_STARTED, dai_data->status_mask); atomic_inc(group_ref); } + dai_data->port_cfg.tdm.num_channels = 1; + dai_data->port_cfg.tdm.slot_mask = 1; + dai_data->port_cfg.tdm.nslots_per_frame = 4; + + dev_dbg(dai->dev, "\n%s:open sec port id %d TDM rate: %d\n" + "dai_data->port_cfg.tdm.slot_mask %x\n" + "dai_data->port_cfg.tdm.nslotsper_frame:%x\n", __func__, + sec_port_id, dai_data->port_cfg.tdm.num_channels, + dai_data->port_cfg.tdm.slot_mask, + dai_data->port_cfg.tdm.nslots_per_frame); + + if (sec_port_id != 0) { + rc = afe_tdm_port_start(sec_port_id, + &dai_data->port_cfg, + dai_data->rate, 4); + if (IS_ERR_VALUE(rc)) { + if (atomic_read(group_ref) == 0) { + afe_port_group_enable(group_id, + NULL, false); + msm_dai_q6_tdm_set_clk(dai_data, + dai->id, false); + } + dev_err(dai->dev, "%s: fail AFE port 0x%x\n", + __func__, sec_port_id); + } else { + set_bit(STATUS_PORT_STARTED, + dai_data->status_mask); + atomic_inc(group_ref); + } + } + /* TODO: need to monitor PCM/MI2S/TDM HW status */ /* NOTE: AFE should error out if HW resource contention */ @@ -5581,6 +5689,8 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, dev_get_drvdata(dai->dev); u16 group_id = dai_data->group_cfg.tdm_cfg.group_id; int group_idx = 0; + u16 prim_port_id = 0; + u16 sec_port_id = 0; atomic_t *group_ref = NULL; group_idx = msm_dai_q6_get_group_idx(dai->id); @@ -5595,11 +5705,30 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, group_ref = &tdm_group_ref[group_idx]; if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) { - rc = afe_close(dai->id); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + prim_port_id = dai->id; + if (dai_data->afe_ebit_unsupported) + sec_port_id = AFE_PORT_ID_PRIMARY_TDM_TX; + } else { + prim_port_id = dai->id; + if (dai_data->afe_ebit_unsupported) + sec_port_id = AFE_PORT_ID_PRIMARY_TDM_RX; + } + + rc = afe_close(prim_port_id); if (IS_ERR_VALUE(rc)) { dev_err(dai->dev, "%s: fail to close AFE port 0x%x\n", - __func__, dai->id); + __func__, prim_port_id); } + + if (sec_port_id != 0) { + rc = afe_close(sec_port_id); + if (IS_ERR_VALUE(rc)) { + dev_err(dai->dev, "%s: fail AFE port 0x%x\n", + __func__, sec_port_id); + } + } + atomic_dec(group_ref); clear_bit(STATUS_PORT_STARTED, dai_data->status_mask); @@ -5608,13 +5737,15 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, rc = afe_port_group_enable(group_id, NULL, false); if (IS_ERR_VALUE(rc)) { - dev_err(dai->dev, "%s: fail to disable AFE group 0x%x\n", + dev_err(dai->dev, + "%s: failed to disable grp 0x%x\n", __func__, group_id); } rc = msm_dai_q6_tdm_set_clk(dai_data, dai->id, false); if (IS_ERR_VALUE(rc)) { - dev_err(dai->dev, "%s: fail to disable AFE clk 0x%x\n", + dev_err(dai->dev, + "%s: fail to disable AFE clk 0x%x\n", __func__, dai->id); } } @@ -6985,6 +7116,32 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev) dai_data->group_cfg.tdm_cfg = tdm_group_cfg; /* copy static num group ports per parent node */ dai_data->num_group_ports = num_tdm_group_ports[group_idx]; + dev_dbg(&pdev->dev, "TX group configuration tdm_dev_id 0x%x\n", + tdm_dev_id); + + dai_data->afe_ebit_unsupported = afe_ebit_unsupported; + + if (tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX || + tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX_1 || + tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX_2 || + tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX_3) { + dev_dbg(&pdev->dev, "Copy TX group config id %d\n", tdm_dev_id); + /*memcpy (&group_cfg_tx,&dai_data->group_cfg , + sizeof(dai_data->group_cfg));*/ + memcpy(&group_cfg_tx.group_cfg, + &dai_data->group_cfg.group_cfg , + sizeof(dai_data->group_cfg.group_cfg)); + memcpy(&group_cfg_tx.group_enable, + &dai_data->group_cfg.group_enable, + sizeof(dai_data->group_cfg.group_enable)); + memcpy(&group_cfg_tx.tdm_cfg, + &dai_data->group_cfg.tdm_cfg, + sizeof(dai_data->group_cfg.tdm_cfg)); + dev_dbg(&pdev->dev, + "Copy TX group configuration Successfully tdm_id %d\n", + tdm_dev_id); + } + dev_set_drvdata(&pdev->dev, dai_data); From 5715752edd0fb0281ad453b4449b4be811d6f691 Mon Sep 17 00:00:00 2001 From: Bala Kishore Pati Date: Fri, 27 Oct 2017 18:53:28 +0530 Subject: [PATCH 040/392] ASoC: msm: enable group config for both tx and rx Add support to enable group config for tdm tx and rx ports.On platform where ebit is unsupported it is expected to start tx and rx ports at a time. Ensure to start both tdm tx and rx group as group devices. Change-Id: Idb995c8215ccad147612b85bf38b289fb24391f2 Signed-off-by: Bala Kishore Pati --- sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c | 176 +++++++++++++++++++++----- 1 file changed, 146 insertions(+), 30 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 4b1159d3774b..1820a2131a97 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -191,6 +191,7 @@ struct msm_dai_q6_auxpcm_dai_data { }; static union afe_port_group_config group_cfg_tx; +static union afe_port_group_config group_cfg_rx; struct msm_dai_q6_tdm_dai_data { DECLARE_BITMAP(status_mask, STATUS_MAX); @@ -5522,24 +5523,34 @@ static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream, custom_tdm_header->header[6], custom_tdm_header->header[7]); } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + group_cfg_tx.tdm_cfg.num_channels = + dai_data->group_cfg.tdm_cfg.num_channels; + group_cfg_tx.tdm_cfg.sample_rate = + dai_data->group_cfg.tdm_cfg.sample_rate; + group_cfg_tx.tdm_cfg.bit_width = + dai_data->group_cfg.tdm_cfg.bit_width; + group_cfg_tx.tdm_cfg.nslots_per_frame = + dai_data->group_cfg.tdm_cfg.nslots_per_frame; + group_cfg_tx.tdm_cfg.slot_width = + dai_data->group_cfg.tdm_cfg.slot_width; + group_cfg_tx.tdm_cfg.slot_mask = + dai_data->group_cfg.tdm_cfg.slot_mask; + } else { + group_cfg_rx.tdm_cfg.num_channels = + dai_data->group_cfg.tdm_cfg.num_channels; + group_cfg_rx.tdm_cfg.sample_rate = + dai_data->group_cfg.tdm_cfg.sample_rate; + group_cfg_rx.tdm_cfg.bit_width = + dai_data->group_cfg.tdm_cfg.bit_width; + group_cfg_rx.tdm_cfg.nslots_per_frame = + dai_data->group_cfg.tdm_cfg.nslots_per_frame; + group_cfg_rx.tdm_cfg.slot_width = + dai_data->group_cfg.tdm_cfg.slot_width; + group_cfg_rx.tdm_cfg.slot_mask = + dai_data->group_cfg.tdm_cfg.slot_mask; - memcpy(&group_cfg_tx.group_cfg, &dai_data->group_cfg.group_cfg, - sizeof(dai_data->group_cfg.group_cfg)); - memcpy(&group_cfg_tx.group_enable, &dai_data->group_cfg.group_enable, - sizeof(dai_data->group_cfg.group_enable)); - memcpy(&group_cfg_tx.tdm_cfg, &dai_data->group_cfg.tdm_cfg, - sizeof(dai_data->group_cfg.tdm_cfg)); - pr_debug("%s: TDM GROUP:\n" - "num_channels=%d sample_rate=%d bit_width=%d\n" - "nslots_per_frame=%d slot_width=%d slot_mask=0x%x\n", - __func__, - group_cfg_tx.tdm_cfg.num_channels, - group_cfg_tx.tdm_cfg.sample_rate, - group_cfg_tx.tdm_cfg.bit_width, - group_cfg_tx.tdm_cfg.nslots_per_frame, - group_cfg_tx.tdm_cfg.slot_width, - group_cfg_tx.tdm_cfg.slot_mask); - + } return 0; } @@ -5550,10 +5561,13 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, struct msm_dai_q6_tdm_dai_data *dai_data = dev_get_drvdata(dai->dev); u16 group_id = dai_data->group_cfg.tdm_cfg.group_id; + u16 sec_group_id = 0; int group_idx = 0; + int sec_group_idx = 0; u16 prim_port_id = 0; u16 sec_port_id = 0; atomic_t *group_ref = NULL; + atomic_t *sec_group_ref = NULL; group_idx = msm_dai_q6_get_group_idx(dai->id); if (group_idx < 0) { @@ -5578,13 +5592,14 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, rc = msm_dai_q6_tdm_set_clk(dai_data, dai->id, true); if (IS_ERR_VALUE(rc)) { - dev_err(dai->dev, "%s: fail to enable AFE clk 0x%x\n", + dev_err(dai->dev, + "%s:AFE CLK enable fail 0x%x\n", __func__, dai->id); goto rtn; } } if (dai_data->num_group_ports > 1) { - dev_dbg(dai->dev, "%s:enable RX afe group\n", + dev_dbg(dai->dev, "%s:enable afe group\n", __func__); rc = afe_port_group_enable(group_id, &dai_data->group_cfg, true); @@ -5605,12 +5620,64 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { prim_port_id = dai->id; - if (dai_data->afe_ebit_unsupported) + if (dai_data->afe_ebit_unsupported) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_TX; + sec_group_id = + AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX; + sec_group_idx = + msm_dai_q6_get_group_idx(sec_group_id); + if (sec_group_idx < 0) { + dev_err(dai->dev, "%s port id 0x%x\n" + "not supported\n", __func__, + sec_group_id); + goto rtn; + } + sec_group_ref = &tdm_group_ref[sec_group_idx]; + if (atomic_read(sec_group_ref) == 0) { + rc = afe_port_group_enable( + sec_group_id, + &group_cfg_tx, + true); + if (IS_ERR_VALUE(rc)) { + dev_err(dai->dev, + "%s:failed to\n" + "enable grp\n" + "%x\n", __func__, + group_id); + goto rtn; + } + } + } } else { prim_port_id = dai->id; - if (dai_data->afe_ebit_unsupported) + if (dai_data->afe_ebit_unsupported) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_RX; + sec_group_id = + AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX; + sec_group_idx = + msm_dai_q6_get_group_idx(sec_group_id); + if (sec_group_idx < 0) { + dev_err(dai->dev, "%s port id 0x%x\n" + " not supported\n", __func__, + sec_group_id); + goto rtn; + } + sec_group_ref = &tdm_group_ref[sec_group_idx]; + if (atomic_read(sec_group_ref) == 0) { + rc = afe_port_group_enable( + sec_group_id, + &group_cfg_rx, + true); + if (IS_ERR_VALUE(rc)) { + dev_err(dai->dev, + "%s:failed to\n" + "enable grp\n" + "%x\n", __func__, + group_id); + goto rtn; + } + } + } } dev_dbg(dai->dev, "\n%s:open prim port id %d TDM rate: %d\n" "dai_data->port_cfg.tdm.slot_mask %x\n" @@ -5667,7 +5734,7 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, } else { set_bit(STATUS_PORT_STARTED, dai_data->status_mask); - atomic_inc(group_ref); + atomic_inc(sec_group_ref); } } @@ -5688,10 +5755,13 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, struct msm_dai_q6_tdm_dai_data *dai_data = dev_get_drvdata(dai->dev); u16 group_id = dai_data->group_cfg.tdm_cfg.group_id; + u16 sec_group_id = 0; int group_idx = 0; + int sec_group_idx = 0; u16 prim_port_id = 0; u16 sec_port_id = 0; atomic_t *group_ref = NULL; + atomic_t *sec_group_ref = NULL; group_idx = msm_dai_q6_get_group_idx(dai->id); if (group_idx < 0) { @@ -5707,14 +5777,37 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { prim_port_id = dai->id; - if (dai_data->afe_ebit_unsupported) + if (dai_data->afe_ebit_unsupported) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_TX; + sec_group_id = + AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX; + sec_group_idx = + msm_dai_q6_get_group_idx(sec_group_id); + if (sec_group_idx < 0) { + dev_err(dai->dev, "%s port id 0x%x\n" + "not supported\n", + __func__, sec_group_id); + return; + } + sec_group_ref = &tdm_group_ref[sec_group_idx]; + } } else { prim_port_id = dai->id; - if (dai_data->afe_ebit_unsupported) + if (dai_data->afe_ebit_unsupported) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_RX; + sec_group_id = + AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX; + sec_group_idx = + msm_dai_q6_get_group_idx(sec_group_id); + if (sec_group_idx < 0) { + dev_err(dai->dev, "%s port id 0x%x\n" + "not supported\n", + __func__, sec_group_id); + return; + } + sec_group_ref = &tdm_group_ref[sec_group_idx]; + } } - rc = afe_close(prim_port_id); if (IS_ERR_VALUE(rc)) { dev_err(dai->dev, "%s: fail to close AFE port 0x%x\n", @@ -5727,6 +5820,7 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, dev_err(dai->dev, "%s: fail AFE port 0x%x\n", __func__, sec_port_id); } + atomic_dec(sec_group_ref); } atomic_dec(group_ref); @@ -5749,7 +5843,16 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, __func__, dai->id); } } - + if (dai_data->afe_ebit_unsupported) { + if (atomic_read(sec_group_ref) == 0) { + rc = afe_port_group_enable(sec_group_id, + NULL, false); + if (IS_ERR_VALUE(rc)) { + dev_err(dai->dev, "%s:failed to\n" + "enable grp %x\n", __func__, group_id); + } + } + } /* TODO: need to monitor PCM/MI2S/TDM HW status */ /* NOTE: AFE should error out if HW resource contention */ @@ -7125,9 +7228,6 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev) tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX_1 || tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX_2 || tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX_3) { - dev_dbg(&pdev->dev, "Copy TX group config id %d\n", tdm_dev_id); - /*memcpy (&group_cfg_tx,&dai_data->group_cfg , - sizeof(dai_data->group_cfg));*/ memcpy(&group_cfg_tx.group_cfg, &dai_data->group_cfg.group_cfg , sizeof(dai_data->group_cfg.group_cfg)); @@ -7141,7 +7241,23 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev) "Copy TX group configuration Successfully tdm_id %d\n", tdm_dev_id); } - + if (tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_RX || + tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_RX_1 || + tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_RX_2 || + tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_RX_3) { + memcpy(&group_cfg_rx.group_cfg, + &dai_data->group_cfg.group_cfg , + sizeof(dai_data->group_cfg.group_cfg)); + memcpy(&group_cfg_rx.group_enable, + &dai_data->group_cfg.group_enable, + sizeof(dai_data->group_cfg.group_enable)); + memcpy(&group_cfg_rx.tdm_cfg, + &dai_data->group_cfg.tdm_cfg, + sizeof(dai_data->group_cfg.tdm_cfg)); + dev_dbg(&pdev->dev, + "Copy RX group configuration Successfully tdm_id %d\n", + tdm_dev_id); + } dev_set_drvdata(&pdev->dev, dai_data); From 114d21fb1a070de9647e3295d04dae9a683fb9c3 Mon Sep 17 00:00:00 2001 From: Bala Kishore Pati Date: Thu, 4 Jan 2018 15:27:47 +0530 Subject: [PATCH 041/392] ASoC: msm: qdspqv2: add check for TDM clock programming Configure TDM clock based on AFE EBIT flag on platforms where it is supported. Change-Id: I900a749b8aae7a87b99b30e1edd20393eb7c4c3b Signed-off-by: Bala Kishore Pati --- sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c | 29 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 1820a2131a97..e178ef92eca7 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -5091,11 +5091,15 @@ static int msm_dai_q6_dai_tdm_remove(struct snd_soc_dai *dai) dev_err(dai->dev, "fail to disable AFE group 0x%x\n", group_id); } - rc = msm_dai_q6_tdm_set_clk(tdm_dai_data, - dai->id, false); - if (IS_ERR_VALUE(rc)) { - dev_err(dai->dev, "%s: fail to disable AFE clk 0x%x\n", + if (!(tdm_dai_data->afe_ebit_unsupported && + !tdm_dai_data->clk_set.clk_freq_in_hz)) { + rc = msm_dai_q6_tdm_set_clk(tdm_dai_data, + dai->id, false); + if (IS_ERR_VALUE(rc)) { + dev_err(dai->dev, + "%s: fail to disable AFE clk 0x%x\n", __func__, dai->id); + } } } } @@ -5726,8 +5730,10 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, if (atomic_read(group_ref) == 0) { afe_port_group_enable(group_id, NULL, false); + if (!(dai_data->afe_ebit_unsupported && + !dai_data->clk_set.clk_freq_in_hz)) msm_dai_q6_tdm_set_clk(dai_data, - dai->id, false); + dai->id, false); } dev_err(dai->dev, "%s: fail AFE port 0x%x\n", __func__, sec_port_id); @@ -5835,12 +5841,15 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, "%s: failed to disable grp 0x%x\n", __func__, group_id); } - rc = msm_dai_q6_tdm_set_clk(dai_data, - dai->id, false); - if (IS_ERR_VALUE(rc)) { - dev_err(dai->dev, + if (!(dai_data->afe_ebit_unsupported && + !dai_data->clk_set.clk_freq_in_hz)) { + rc = msm_dai_q6_tdm_set_clk(dai_data, + dai->id, false); + if (IS_ERR_VALUE(rc)) { + dev_err(dai->dev, "%s: fail to disable AFE clk 0x%x\n", __func__, dai->id); + } } } if (dai_data->afe_ebit_unsupported) { From ce06c500e95c4503c77e4819f53b47d89e8c645c Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Wed, 21 Feb 2018 14:20:14 +0530 Subject: [PATCH 042/392] ASoC: msm: qdsp6v2: support source tracking with TDM interface Add mixer controls and port id for PRIMARY_TDM interface to support source tracking with TDM mics. CRs-Fixed: 2193330 Change-Id: I62fd250e0feb3fbc190fb63d1398fc3082506f47 Signed-off-by: Surendar karka Signed-off-by: Dhanalakshmi Siddani --- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 3b280cebe1ff..471ad025b281 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -9523,6 +9523,9 @@ static int msm_audio_sound_focus_derive_port_id(struct snd_kcontrol *kcontrol, } else if (!strcmp(kcontrol->id.name + strlen(prefix), "QUATERNARY_MI2S")) { *port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX; + } else if (!strcmp(kcontrol->id.name + strlen(prefix), + "PRIMARY_TDM")) { + *port_id = AFE_PORT_ID_PRIMARY_TDM_TX; } else { pr_err("%s: mixer ctl name=%s, could not derive valid port id\n", __func__, kcontrol->id.name); @@ -9742,6 +9745,21 @@ static const struct snd_kcontrol_new msm_source_tracking_controls[] = { .info = msm_source_tracking_info, .get = msm_audio_source_tracking_get, }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Sound Focus Audio Tx PRIMARY_TDM", + .info = msm_sound_focus_info, + .get = msm_audio_sound_focus_get, + .put = msm_audio_sound_focus_put, + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Source Tracking Audio Tx PRIMARY_TDM", + .info = msm_source_tracking_info, + .get = msm_audio_source_tracking_get, + }, }; static int spkr_prot_put_vi_lch_port(struct snd_kcontrol *kcontrol, From 7d6e6ea829521d64e1fa74dd39894ce492b3ce7b Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Mon, 13 Nov 2017 12:18:46 +0530 Subject: [PATCH 043/392] ASoC: msm: qdspqv2: add property to start secondary port MSM8909 chipset holds the limitation where we need to start both RX and TX AFE ports for TDM. Add new property to start corresponding TX/RX port. CRs-Fixed: 2147847 Change-Id: I234918807338fc4324ae731885d8e0415d29c743 Signed-off-by: Surendar karka --- .../bindings/sound/qcom-audio-dev.txt | 3 +++ sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c | 22 +++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 80eb3ed2b4e7..664d867b1bfe 100755 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -1376,6 +1376,9 @@ Required properties: clock rate as zero then afe is not configured for clock. + - qcom,msm-cpudai-tdm-sec-port-start: For chipsets with the limitation where we need + to start both RX and TX AFE ports, this flag is + used to start TX/RX port for RX/TX streams. [Second Level Nodes] diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 1820a2131a97..f667cbd19f07 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -200,12 +200,14 @@ struct msm_dai_q6_tdm_dai_data { u32 bitwidth; u32 num_group_ports; bool afe_ebit_unsupported; + bool sec_port_enable; struct afe_clk_set clk_set; /* hold LPASS clock config. */ union afe_port_group_config group_cfg; /* hold tdm group config */ struct afe_tdm_port_config port_cfg; /* hold tdm config */ }; static bool afe_ebit_unsupported; +static bool tdm_sec_port_enable; /* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command * 0: linear PCM @@ -4142,6 +4144,11 @@ static int msm_dai_tdm_q6_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "afe_ebit_unsupported %d\n", afe_ebit_unsupported); + tdm_sec_port_enable = of_property_read_bool(pdev->dev.of_node, + "qcom,msm-cpudai-tdm-sec-port-enable"); + + dev_dbg(&pdev->dev, "tdm_sec_port_enable %d\n", tdm_sec_port_enable); + /* other initializations within device group */ atomic_set(&tdm_group_ref[group_idx], 0); @@ -5620,7 +5627,7 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { prim_port_id = dai->id; - if (dai_data->afe_ebit_unsupported) { + if (dai_data->sec_port_enable) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_TX; sec_group_id = AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX; @@ -5650,7 +5657,7 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, } } else { prim_port_id = dai->id; - if (dai_data->afe_ebit_unsupported) { + if (dai_data->sec_port_enable) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_RX; sec_group_id = AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX; @@ -5709,7 +5716,6 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, dai_data->port_cfg.tdm.num_channels = 1; dai_data->port_cfg.tdm.slot_mask = 1; - dai_data->port_cfg.tdm.nslots_per_frame = 4; dev_dbg(dai->dev, "\n%s:open sec port id %d TDM rate: %d\n" "dai_data->port_cfg.tdm.slot_mask %x\n" @@ -5721,7 +5727,8 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, if (sec_port_id != 0) { rc = afe_tdm_port_start(sec_port_id, &dai_data->port_cfg, - dai_data->rate, 4); + dai_data->rate, + dai_data->num_group_ports); if (IS_ERR_VALUE(rc)) { if (atomic_read(group_ref) == 0) { afe_port_group_enable(group_id, @@ -5777,7 +5784,7 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { prim_port_id = dai->id; - if (dai_data->afe_ebit_unsupported) { + if (dai_data->sec_port_enable) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_TX; sec_group_id = AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX; @@ -5793,7 +5800,7 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, } } else { prim_port_id = dai->id; - if (dai_data->afe_ebit_unsupported) { + if (dai_data->sec_port_enable) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_RX; sec_group_id = AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX; @@ -5843,7 +5850,7 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, __func__, dai->id); } } - if (dai_data->afe_ebit_unsupported) { + if (dai_data->sec_port_enable) { if (atomic_read(sec_group_ref) == 0) { rc = afe_port_group_enable(sec_group_id, NULL, false); @@ -7223,6 +7230,7 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev) tdm_dev_id); dai_data->afe_ebit_unsupported = afe_ebit_unsupported; + dai_data->sec_port_enable = tdm_sec_port_enable; if (tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX || tdm_dev_id == AFE_PORT_ID_PRIMARY_TDM_TX_1 || From 42f25ae4a04c9c8d8cb804b5ce9a8218528039b8 Mon Sep 17 00:00:00 2001 From: Surendar Karka Date: Fri, 8 Dec 2017 16:00:37 +0530 Subject: [PATCH 044/392] ASoC: msm: qdspqv2: enable secondary group based on group count Enable the secondary port tdm group only if number of groups is more than one. CRs-Fixed: 2147847 Change-Id: I989846f611fab78cbb50a3120c94fc44dc50fb46 Signed-off-by: Surendar karka --- sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index f667cbd19f07..45cef60a232b 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -5629,6 +5629,10 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, prim_port_id = dai->id; if (dai_data->sec_port_enable) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_TX; + sec_group_ref = &tdm_group_ref[sec_group_idx]; + } + if ((dai_data->num_group_ports > 1) && + (dai_data->sec_port_enable)) { sec_group_id = AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX; sec_group_idx = @@ -5639,7 +5643,6 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, sec_group_id); goto rtn; } - sec_group_ref = &tdm_group_ref[sec_group_idx]; if (atomic_read(sec_group_ref) == 0) { rc = afe_port_group_enable( sec_group_id, @@ -5659,6 +5662,10 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, prim_port_id = dai->id; if (dai_data->sec_port_enable) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_RX; + sec_group_ref = &tdm_group_ref[sec_group_idx]; + } + if ((dai_data->num_group_ports > 1) && + (dai_data->sec_port_enable)) { sec_group_id = AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX; sec_group_idx = @@ -5669,7 +5676,6 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, sec_group_id); goto rtn; } - sec_group_ref = &tdm_group_ref[sec_group_idx]; if (atomic_read(sec_group_ref) == 0) { rc = afe_port_group_enable( sec_group_id, @@ -5786,6 +5792,10 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, prim_port_id = dai->id; if (dai_data->sec_port_enable) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_TX; + sec_group_ref = &tdm_group_ref[sec_group_idx]; + } + if ((dai_data->num_group_ports > 1) && + (dai_data->sec_port_enable)) { sec_group_id = AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX; sec_group_idx = @@ -5796,12 +5806,15 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, __func__, sec_group_id); return; } - sec_group_ref = &tdm_group_ref[sec_group_idx]; } } else { prim_port_id = dai->id; if (dai_data->sec_port_enable) { sec_port_id = AFE_PORT_ID_PRIMARY_TDM_RX; + sec_group_ref = &tdm_group_ref[sec_group_idx]; + } + if ((dai_data->num_group_ports > 1) && + (dai_data->sec_port_enable)) { sec_group_id = AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX; sec_group_idx = @@ -5812,7 +5825,6 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, __func__, sec_group_id); return; } - sec_group_ref = &tdm_group_ref[sec_group_idx]; } } rc = afe_close(prim_port_id); @@ -5850,7 +5862,8 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, __func__, dai->id); } } - if (dai_data->sec_port_enable) { + if ((dai_data->num_group_ports > 1) && + (dai_data->sec_port_enable)) { if (atomic_read(sec_group_ref) == 0) { rc = afe_port_group_enable(sec_group_id, NULL, false); From 5cb9b1bdecff0f5bc712c6b0af71d44b4283b712 Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Mon, 11 Dec 2017 15:36:11 +0530 Subject: [PATCH 045/392] ASoC: msm: qdspqv2: add route from MM_DL9 to PRI_MI2S_RX Flunece FFV uses MM_DL9 to record data from PRI_MI2S_RX port. Add route between MM_DL9 to PRI_MI2S_RX. CRs-Fixed: 2156759 Change-Id: I1c7a16c15893ef5cb0db00f00a1a8d78325eb328 Signed-off-by: Surendar karka --- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 3b280cebe1ff..f493a252510e 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -11136,6 +11136,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"}, {"PRI_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"}, {"PRI_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"}, + {"PRI_MI2S_RX Audio Mixer", "MultiMedia9", "MM_DL9"}, {"PRI_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"}, {"PRI_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"}, {"PRI_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"}, From f517f2bca8fa44e62ee8101dbfb48116955fb196 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Wed, 27 Jun 2018 13:00:13 +0530 Subject: [PATCH 046/392] SSM: Remove support for SSM driver SSM driver is not enabled and hence needs deprecation. Remove all the SSM driver references. CRs-Fixed: 2268386 Change-Id: I02f82817023d2fcc6d05a2f0d7eb3aec8f60a7d5 Signed-off-by: Manoj Prabhu B --- .../devicetree/bindings/platform/msm/ssm.txt | 13 - drivers/platform/msm/Kconfig | 10 - drivers/platform/msm/Makefile | 1 - drivers/platform/msm/ssm.c | 516 ------------------ drivers/platform/msm/ssm.h | 90 --- 5 files changed, 630 deletions(-) delete mode 100644 Documentation/devicetree/bindings/platform/msm/ssm.txt delete mode 100644 drivers/platform/msm/ssm.c delete mode 100644 drivers/platform/msm/ssm.h diff --git a/Documentation/devicetree/bindings/platform/msm/ssm.txt b/Documentation/devicetree/bindings/platform/msm/ssm.txt deleted file mode 100644 index 7df3efd66577..000000000000 --- a/Documentation/devicetree/bindings/platform/msm/ssm.txt +++ /dev/null @@ -1,13 +0,0 @@ -* Qualcomm Technologies, Inc. Secure Service Module driver - -This module enables framework to which a client can register itself -specifying different attributes and defining various permission levels -associated with different combination of attribute values and mode of the system. - -Required properties: -- compatible: Must be "qcom,ssm" - -Example: - qcom,ssm { - compatible = "qcom,ssm"; - }; \ No newline at end of file diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index 0774fe4d29aa..198408ad3ea9 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -194,16 +194,6 @@ config IPA_UT The user interface to run and control the tests is debugfs file system. -config SSM - tristate "QTI Secure Service Module" - depends on QSEECOM - depends on MSM_SMD - help - Provides an interface for OEM driver to communicate with Trustzone - and modem for key exchange and mode change. - This driver uses Secure Channel Manager interface for trustzone - communication and communicates with modem over SMD channel. - config MSM_MHI tristate "Modem Host Interface Driver" help diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile index 1ecb76f6a76b..5507a12a7ed3 100644 --- a/drivers/platform/msm/Makefile +++ b/drivers/platform/msm/Makefile @@ -25,4 +25,3 @@ obj-$(CONFIG_QPNP_VIBRATOR) += qpnp-vibrator.o obj-$(CONFIG_MSM_AVTIMER) += avtimer.o obj-$(CONFIG_MSM_11AD) += msm_11ad/ obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/ -obj-$(CONFIG_SSM) += ssm.o \ No newline at end of file diff --git a/drivers/platform/msm/ssm.c b/drivers/platform/msm/ssm.c deleted file mode 100644 index 6a2909b8c5f4..000000000000 --- a/drivers/platform/msm/ssm.c +++ /dev/null @@ -1,516 +0,0 @@ -/* Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * QTI Secure Service Module(SSM) driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../misc/qseecom_kernel.h" -#include "ssm.h" - -/* Macros */ -#define SSM_DEV_NAME "ssm" -#define MPSS_SUBSYS 0 -#define SSM_INFO_CMD_ID 1 -#define MAX_APP_NAME_SIZE 32 -#define SSM_MSG_LEN 200 -#define SSM_MSG_FIELD_LEN 11 -#define ATOM_MSG_LEN (SSM_MSG_FIELD_LEN + SSM_MSG_LEN + 40) - -#define TZAPP_NAME "SsmApp" -#define CHANNEL_NAME "SSM_RTR_MODEM_APPS" - -/* SSM driver structure.*/ -struct ssm_driver { - int32_t app_status; - int32_t update_status; - unsigned char *channel_name; - unsigned char *smd_buffer; - struct device *dev; - smd_channel_t *ch; - struct work_struct ipc_work; - struct mutex mutex; - struct qseecom_handle *qseecom_handle; - struct tzapp_get_mode_info_rsp *resp; - bool key_status; - bool ready; -}; - -static struct ssm_driver *ssm_drv; - -static unsigned int getint(char *buff, unsigned long *res) -{ - char value[SSM_MSG_FIELD_LEN]; - - memcpy(value, buff, SSM_MSG_FIELD_LEN); - value[SSM_MSG_FIELD_LEN - 1] = '\0'; - - return kstrtoul(skip_spaces(value), 10, res); -} - -/* - * Setup CMD/RSP pointers. - */ -static void setup_cmd_rsp_buffers(struct qseecom_handle *handle, void **cmd, - int *cmd_len, void **resp, int *resp_len) -{ - *cmd = handle->sbuf; - if (*cmd_len & QSEECOM_ALIGN_MASK) - *cmd_len = QSEECOM_ALIGN(*cmd_len); - - *resp = handle->sbuf + *cmd_len; - if (*resp_len & QSEECOM_ALIGN_MASK) - *resp_len = QSEECOM_ALIGN(*resp_len); -} - -/* - * Send packet to modem over SMD channel. - */ -static int update_modem(enum ssm_ipc_req ipc_req, struct ssm_driver *ssm, - int length, char *data) -{ - unsigned int packet_len = length + SSM_MSG_FIELD_LEN; - int rc = 0, count; - - snprintf(ssm->smd_buffer, SSM_MSG_FIELD_LEN + 1, "%10u|", ipc_req); - memcpy(ssm->smd_buffer + SSM_MSG_FIELD_LEN, data, length); - - if (smd_write_avail(ssm->ch) < packet_len) { - dev_err(ssm->dev, "Not enough space dropping request\n"); - rc = -ENOSPC; - goto out; - } - - count = smd_write(ssm->ch, ssm->smd_buffer, packet_len); - if (count < packet_len) { - dev_err(ssm->dev, "smd_write failed for %d\n", ipc_req); - rc = -EIO; - } - -out: - return rc; -} - -/* - * Header Format - * Each member of header is of 10 byte (ASCII). - * Each entry is separated by '|' delimiter. - * |<-10 bytes->|<-10 bytes->| - * |-------------------------| - * | IPC code | error code | - * |-------------------------| - * - */ -static int decode_packet(char *buffer, struct ssm_common_msg *pkt) -{ - int rc; - - rc = getint(buffer, (unsigned long *)&pkt->ipc_req); - if (rc < 0) - return -EINVAL; - - buffer += SSM_MSG_FIELD_LEN; - rc = getint(buffer, (unsigned long *)&pkt->err_code); - if (rc < 0) - return -EINVAL; - - dev_dbg(ssm_drv->dev, "req %d error code %d\n", - pkt->ipc_req, pkt->err_code); - return 0; -} - -static void process_message(struct ssm_common_msg pkt, struct ssm_driver *ssm) -{ - - switch (pkt.ipc_req) { - - case SSM_MTOA_MODE_UPDATE_STATUS: - if (pkt.err_code) { - dev_err(ssm->dev, "Modem mode update failed\n"); - ssm->update_status = FAILED; - } else - ssm->update_status = SUCCESS; - - dev_dbg(ssm->dev, "Modem mode update status %d\n", - pkt.err_code); - break; - - default: - dev_dbg(ssm->dev, "Invalid message\n"); - break; - }; -} - -/* - * Work function to handle and process packets coming from modem. - */ -static void ssm_app_modem_work_fn(struct work_struct *work) -{ - int sz, rc; - struct ssm_common_msg pkt; - struct ssm_driver *ssm; - - ssm = container_of(work, struct ssm_driver, ipc_work); - - mutex_lock(&ssm->mutex); - sz = smd_cur_packet_size(ssm->ch); - if ((sz < SSM_MSG_FIELD_LEN) || (sz > ATOM_MSG_LEN)) { - dev_dbg(ssm_drv->dev, "Garbled message size\n"); - goto unlock; - } - - if (smd_read_avail(ssm->ch) < sz) { - dev_err(ssm_drv->dev, "SMD error data in channel\n"); - goto unlock; - } - - if (smd_read(ssm->ch, ssm->smd_buffer, sz) != sz) { - dev_err(ssm_drv->dev, "Incomplete data\n"); - goto unlock; - } - - rc = decode_packet(ssm->smd_buffer, &pkt); - if (rc < 0) { - dev_err(ssm_drv->dev, "Corrupted header\n"); - goto unlock; - } - - process_message(pkt, ssm); - -unlock: - mutex_unlock(&ssm->mutex); -} - -/* - * MODEM-APPS smd channel callback function. - */ -static void modem_request(void *ctxt, unsigned event) -{ - struct ssm_driver *ssm; - - ssm = (struct ssm_driver *)ctxt; - - switch (event) { - case SMD_EVENT_OPEN: - case SMD_EVENT_CLOSE: - dev_dbg(ssm->dev, "SMD port status changed\n"); - break; - case SMD_EVENT_DATA: - if (smd_read_avail(ssm->ch) > 0) - schedule_work(&ssm->ipc_work); - break; - }; -} - -/* - * Load SSM application in TZ and start application: - */ -static int ssm_load_app(struct ssm_driver *ssm) -{ - int rc; - - /* Load the APP */ - rc = qseecom_start_app(&ssm->qseecom_handle, TZAPP_NAME, SZ_4K); - if (rc < 0) { - dev_err(ssm->dev, "Unable to load SSM app\n"); - ssm->app_status = FAILED; - return -EIO; - } - - ssm->app_status = SUCCESS; - return 0; -} - -static struct ssm_platform_data *populate_ssm_pdata(struct device *dev) -{ - struct ssm_platform_data *pdata; - - pdata = devm_kzalloc(dev, sizeof(struct ssm_platform_data), - GFP_KERNEL); - if (!pdata) - return NULL; - - pdata->need_key_exchg = - of_property_read_bool(dev->of_node, "qcom,need-keyexhg"); - - pdata->channel_name = CHANNEL_NAME; - - return pdata; -} - -static int ssm_probe(struct platform_device *pdev) -{ - int rc; - struct ssm_platform_data *pdata; - struct ssm_driver *drv; - - if (pdev->dev.of_node) - pdata = populate_ssm_pdata(&pdev->dev); - else - pdata = pdev->dev.platform_data; - - if (!pdata) { - dev_err(&pdev->dev, "Empty platform data\n"); - return -ENOMEM; - } - - drv = devm_kzalloc(&pdev->dev, sizeof(struct ssm_driver), - GFP_KERNEL); - if (!drv) - return -ENOMEM; - - /* Allocate response buffer */ - drv->resp = devm_kzalloc(&pdev->dev, - sizeof(struct tzapp_get_mode_info_rsp), - GFP_KERNEL); - if (!drv->resp) { - devm_kfree(&pdev->dev, drv); - rc = -ENOMEM; - goto exit; - } - - /* Initialize the driver structure */ - drv->app_status = RETRY; - drv->ready = false; - drv->update_status = FAILED; - mutex_init(&drv->mutex); - drv->key_status = !pdata->need_key_exchg; - drv->channel_name = (char *)pdata->channel_name; - INIT_WORK(&drv->ipc_work, ssm_app_modem_work_fn); - - /* Allocate memory for smd buffer */ - drv->smd_buffer = devm_kzalloc(&pdev->dev, - (sizeof(char) * ATOM_MSG_LEN), GFP_KERNEL); - if (!drv->smd_buffer) { - devm_kfree(&pdev->dev, drv->resp); - devm_kfree(&pdev->dev, drv); - rc = -ENOMEM; - goto exit; - } - - drv->dev = &pdev->dev; - ssm_drv = drv; - platform_set_drvdata(pdev, ssm_drv); - - dev_dbg(&pdev->dev, "probe success\n"); - return 0; - -exit: - mutex_destroy(&drv->mutex); - platform_set_drvdata(pdev, NULL); - return rc; - -} - -static int ssm_remove(struct platform_device *pdev) -{ - - if (!ssm_drv) - return 0; - /* - * Step to exit - * 1. set ready to 0 (oem access closed). - * 2. Close SMD modem connection closed. - * 3. cleanup ion. - */ - ssm_drv->ready = false; - smd_close(ssm_drv->ch); - flush_work(&ssm_drv->ipc_work); - - /* Shutdown tzapp */ - dev_dbg(&pdev->dev, "Shutting down TZapp\n"); - qseecom_shutdown_app(&ssm_drv->qseecom_handle); - - /* freeing the memory allocations - for the driver and the buffer */ - devm_kfree(&pdev->dev, ssm_drv->smd_buffer); - devm_kfree(&pdev->dev, ssm_drv->resp); - devm_kfree(&pdev->dev, ssm_drv); - - return 0; -} - -static struct of_device_id ssm_match_table[] = { - { - .compatible = "qcom,ssm", - }, - {} -}; - -static struct platform_driver ssm_pdriver = { - .probe = ssm_probe, - .remove = ssm_remove, - .driver = { - .name = SSM_DEV_NAME, - .owner = THIS_MODULE, - .of_match_table = ssm_match_table, - }, -}; -module_platform_driver(ssm_pdriver); - -/* - * Interface for external OEM driver. - * This interface supports following functionalities: - * 1. Set mode (encrypted mode and it's length is passed as parameter). - * 2. Set mode from TZ (read encrypted mode from TZ) - * 3. Get status of mode update. - * - */ -int ssm_oem_driver_intf(int cmd, char *mode, int len) -{ - int rc, req_len, resp_len; - struct tzapp_get_mode_info_req *get_mode_req; - struct tzapp_get_mode_info_rsp *get_mode_resp; - - /* If ssm_drv is NULL, probe failed */ - if (!ssm_drv) - return -ENODEV; - - mutex_lock(&ssm_drv->mutex); - - if (ssm_drv->app_status == RETRY) { - /* Load TZAPP */ - rc = ssm_load_app(ssm_drv); - if (rc) { - rc = -ENODEV; - goto unlock; - } - } else if (ssm_drv->app_status == FAILED) { - rc = -ENODEV; - goto unlock; - } - - /* Open modem SMD interface */ - if (!ssm_drv->ready) { - rc = smd_named_open_on_edge(ssm_drv->channel_name, - SMD_APPS_MODEM, - &ssm_drv->ch, - ssm_drv, - modem_request); - if (rc) { - rc = -EAGAIN; - goto unlock; - } else - ssm_drv->ready = true; - } - - /* Try again modem key-exchange not yet done.*/ - if (!ssm_drv->key_status) { - rc = -EAGAIN; - goto unlock; - } - - /* Set return status to success */ - rc = 0; - - switch (cmd) { - case SSM_READY: - break; - - case SSM_MODE_INFO_READY: - ssm_drv->update_status = RETRY; - /* Fill command structure */ - req_len = sizeof(struct tzapp_get_mode_info_req); - resp_len = sizeof(struct tzapp_get_mode_info_rsp); - setup_cmd_rsp_buffers(ssm_drv->qseecom_handle, - (void **)&get_mode_req, &req_len, - (void **)&get_mode_resp, &resp_len); - get_mode_req->tzapp_ssm_cmd = GET_ENC_MODE; - - rc = qseecom_set_bandwidth(ssm_drv->qseecom_handle, 1); - if (rc) { - ssm_drv->update_status = FAILED; - dev_err(ssm_drv->dev, "set bandwidth failed\n"); - rc = -EIO; - break; - } - rc = qseecom_send_command(ssm_drv->qseecom_handle, - (void *)get_mode_req, req_len, - (void *)get_mode_resp, resp_len); - if (rc || get_mode_resp->status) { - ssm_drv->update_status = FAILED; - break; - } - rc = qseecom_set_bandwidth(ssm_drv->qseecom_handle, 0); - if (rc) { - ssm_drv->update_status = FAILED; - dev_err(ssm_drv->dev, "clear bandwidth failed\n"); - rc = -EIO; - break; - } - - if (get_mode_resp->enc_mode_len > ENC_MODE_MAX_SIZE) { - ssm_drv->update_status = FAILED; - rc = -EINVAL; - break; - } - /* Send mode_info to modem */ - rc = update_modem(SSM_ATOM_MODE_UPDATE, ssm_drv, - get_mode_resp->enc_mode_len, - get_mode_resp->enc_mode_info); - if (rc) - ssm_drv->update_status = FAILED; - break; - - case SSM_SET_MODE: - ssm_drv->update_status = RETRY; - - if (len > ENC_MODE_MAX_SIZE) { - ssm_drv->update_status = FAILED; - rc = -EINVAL; - break; - } - memcpy(ssm_drv->resp->enc_mode_info, mode, len); - ssm_drv->resp->enc_mode_len = len; - - /* Send mode_info to modem */ - rc = update_modem(SSM_ATOM_MODE_UPDATE, ssm_drv, - ssm_drv->resp->enc_mode_len, - ssm_drv->resp->enc_mode_info); - if (rc) - ssm_drv->update_status = FAILED; - break; - - case SSM_GET_MODE_STATUS: - rc = ssm_drv->update_status; - break; - - default: - rc = -EINVAL; - dev_err(ssm_drv->dev, "Invalid command\n"); - break; - }; - -unlock: - mutex_unlock(&ssm_drv->mutex); - return rc; -} - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("QTI Secure Service Module"); - diff --git a/drivers/platform/msm/ssm.h b/drivers/platform/msm/ssm.h deleted file mode 100644 index ee4f1bc1d83f..000000000000 --- a/drivers/platform/msm/ssm.h +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __SSM_H_ -#define __SSM_H_ - -#define MAX_APP_NAME_SIZE 32 -#define ENC_MODE_MAX_SIZE 200 - -/* tzapp response.*/ -enum tz_response { - RESULT_SUCCESS = 0, - RESULT_FAILURE = 0xFFFFFFFF, -}; - -/* tzapp command list.*/ -enum tz_commands { - ENC_MODE, - GET_ENC_MODE, - KEY_EXCHANGE = 11, -}; - -/* MODEM/SSM command list.*/ -enum ssm_ipc_req { - SSM_IPC_MIN = 0x0000AAAB, - SSM_ATOM_MODE_UPDATE, - SSM_MTOA_MODE_UPDATE_STATUS = SSM_IPC_MIN + 4, - SSM_INVALID_REQ, -}; - -/* OEM request commands list.*/ -enum oem_req { - SSM_READY, - SSM_MODE_INFO_READY, - SSM_SET_MODE, - SSM_GET_MODE_STATUS, - SSM_INVALID, -}; - -/* Modem mode update status.*/ -enum modem_mode_status { - SUCCESS, - RETRY, - FAILED = -1, -}; - -/* tzapp encode mode request.*/ -__packed struct tzapp_mode_enc_req { - uint32_t tzapp_ssm_cmd; - uint8_t mode_info[4]; -}; - -/* tzapp encode mode response.*/ -__packed struct tzapp_mode_enc_rsp { - uint32_t tzapp_ssm_cmd; - uint8_t enc_mode_info[ENC_MODE_MAX_SIZE]; - uint32_t enc_mode_len; - uint32_t status; -}; - -/* tzapp get mode request.*/ -__packed struct tzapp_get_mode_info_req { - uint32_t tzapp_ssm_cmd; -}; - -/* tzapp get mode response.*/ -__packed struct tzapp_get_mode_info_rsp { - uint32_t tzapp_ssm_cmd; - uint8_t enc_mode_info[ENC_MODE_MAX_SIZE]; - uint32_t enc_mode_len; - uint32_t status; -}; - -/* Modem/SSM packet format.*/ -struct ssm_common_msg { - enum ssm_ipc_req ipc_req; - int err_code; - -}; - -#endif From 6cc4e2a21ed42cbca03991b963f347a7740516d9 Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Thu, 14 Dec 2017 14:52:17 +0530 Subject: [PATCH 047/392] ASoC: msm: enable TDM mics with gpio controlled TDM mics are controlled by switch, drive corresponding gpio to output high to enable switch. CRs-Fixed: 2164870 Change-Id: I169d5726d43494922aa027fb28c6e9eef7dcf0c5 Signed-off-by: Surendar karka Signed-off-by: Dhanalakshmi Siddani --- .../bindings/sound/qcom-audio-dev.txt | 3 +++ sound/soc/msm/apq8009-i2s-ext-codec.c | 20 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 80c8fd14ef94..877e117cf68e 100755 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -1963,6 +1963,9 @@ Optional properties: - qcom,wsa-devs: This property contains list of wsa codec names. The names should comply with the wsa nodes configurations. - qcom,wsa-aux-dev-prefix: This property contains list of wsa codec prefixes. +- qcom,tdm-i2s-switch-enable: For chipsets where tdm mics are controlled by + switch, drive corresponding gpio to output high + to enable switch. Example: sound { diff --git a/sound/soc/msm/apq8009-i2s-ext-codec.c b/sound/soc/msm/apq8009-i2s-ext-codec.c index b6790e2682a9..8b10471d4832 100644 --- a/sound/soc/msm/apq8009-i2s-ext-codec.c +++ b/sound/soc/msm/apq8009-i2s-ext-codec.c @@ -1,4 +1,4 @@ - /* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + /* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2733,6 +2733,7 @@ static int apq8009_asoc_machine_probe(struct platform_device *pdev) const char *mclk = "qcom,msm-mclk-freq"; const char *type = NULL; int ret, id; + int tdm_i2s_switch_enable = -EINVAL; pdata = devm_kzalloc(&pdev->dev, sizeof(struct apq8009_asoc_mach_data), GFP_KERNEL); @@ -2830,6 +2831,23 @@ static int apq8009_asoc_machine_probe(struct platform_device *pdev) ret); goto err; } + + tdm_i2s_switch_enable = of_get_named_gpio(pdev->dev.of_node, + "qcom,tdm-i2s-switch-enable", 0); + if (tdm_i2s_switch_enable >= 0) { + dev_dbg(&pdev->dev, "%s: tdm switch gpio %d", __func__, + tdm_i2s_switch_enable); + ret = gpio_request(tdm_i2s_switch_enable, "TDM_RESET"); + if (ret) { + pr_err("%s: Failed to request gpio\n", __func__); + goto err; + } + gpio_direction_output(tdm_i2s_switch_enable, 1); + } else + dev_err(&pdev->dev, "Looking up %s property in node %s failed\n", + "qcom,tdm-i2s-switch-enable", + pdev->dev.of_node->full_name); + return 0; err: if (pdata->vaddr_gpio_mux_spkr_ctl) From a3706e7bd56870ad628f5a078536c3edc303a53b Mon Sep 17 00:00:00 2001 From: Surendar Karka Date: Wed, 7 Feb 2018 16:13:15 +0530 Subject: [PATCH 048/392] ASoC: msm: dynamically control i2s switch gpio Set i2s switch gpio to output high when TDM BE is started and make the gpio to output low so that BT can use the i2s lines. CRs-Fixed: 2185727 Change-Id: I5fd1a3687a42fd6cc171af35c2165b0c9259b93c Signed-off-by: Surendar karka --- sound/soc/msm/apq8009-i2s-ext-codec.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/msm/apq8009-i2s-ext-codec.c b/sound/soc/msm/apq8009-i2s-ext-codec.c index 8b10471d4832..b29273083ba9 100644 --- a/sound/soc/msm/apq8009-i2s-ext-codec.c +++ b/sound/soc/msm/apq8009-i2s-ext-codec.c @@ -144,6 +144,7 @@ static int apq8009_auxpcm_rate = 8000; static atomic_t pri_mi2s_clk_ref; static atomic_t quat_mi2s_clk_ref; static atomic_t auxpcm_mi2s_clk_ref; +static int tdm_i2s_switch_enable = -EINVAL; static int apq8009_enable_extcodec_ext_clk(struct snd_soc_codec *codec, int enable, bool dapm); @@ -1480,6 +1481,9 @@ static int msm_tdm_startup(struct snd_pcm_substream *substream) if (ret < 0) pr_err("%s: failed to activate primary TDM gpio set\n", __func__); + /* Enable I2S switch to turn on TDM mics for SOM*/ + if (tdm_i2s_switch_enable >= 0) + gpio_direction_output(tdm_i2s_switch_enable, 1); break; default: pr_err("dai id 0x%x not supported", cpu_dai->id); @@ -1517,6 +1521,9 @@ static void msm_tdm_shutdown(struct snd_pcm_substream *substream) __func__, "pri_tdm"); return; } + + if (tdm_i2s_switch_enable >= 0) + gpio_direction_output(tdm_i2s_switch_enable, 0); break; default: break; @@ -2733,7 +2740,6 @@ static int apq8009_asoc_machine_probe(struct platform_device *pdev) const char *mclk = "qcom,msm-mclk-freq"; const char *type = NULL; int ret, id; - int tdm_i2s_switch_enable = -EINVAL; pdata = devm_kzalloc(&pdev->dev, sizeof(struct apq8009_asoc_mach_data), GFP_KERNEL); @@ -2842,7 +2848,6 @@ static int apq8009_asoc_machine_probe(struct platform_device *pdev) pr_err("%s: Failed to request gpio\n", __func__); goto err; } - gpio_direction_output(tdm_i2s_switch_enable, 1); } else dev_err(&pdev->dev, "Looking up %s property in node %s failed\n", "qcom,tdm-i2s-switch-enable", From b0356e443736e256c01842cfa49c45e250fad908 Mon Sep 17 00:00:00 2001 From: gaolez Date: Thu, 14 Jun 2018 11:52:04 +0800 Subject: [PATCH 049/392] msm: wlan: Update regulatory database Update country AL's frequency range. Update country JP's tx power. Update country MU's tx power and frequency range. Update country PA's tx power and frequency range. Update country UA's tx power and frequency range. Update country KR's tx power and frequency range. Update country QA's tx power and frequency range. Change-Id: Ia81cdb687e1cb8df118216a37518d69e3f6b35a2 CRs-Fixed: 2260411 Signed-off-by: Gaole Zhang --- net/wireless/db.txt | 49 +++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 9675fbd3a17d..6d2d3934ee61 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -37,9 +37,10 @@ country AI: DFS-ETSI country AL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5150 - 5250 @ 80), (23), AUTO-BW - (5250 - 5350 @ 80), (23), DFS, AUTO-BW - (5470 - 5710 @ 160), (30), DFS + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country AM: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -729,9 +730,9 @@ country JO: country JP: DFS-JP (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW, NO-OUTDOOR - (5250 - 5330 @ 80), (20), DFS, AUTO-BW, NO-OUTDOOR - (5490 - 5710 @ 160), (20), DFS + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (26), DFS, AUTO-BW, NO-OUTDOOR + (5490 - 5710 @ 160), (26), DFS # 60 GHz band channels 2-4 at 10mW, # ref: http://www.arib.or.jp/english/html/overview/doc/1-STD-T74v1_1.pdf (59000 - 66000 @ 2160), (10 mW) @@ -758,8 +759,8 @@ country KN: DFS-FCC country KR: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW - (5490 - 5730 @ 160), (30), DFS + (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5490 - 5710 @ 160), (30), DFS (5735 - 5835 @ 80), (30) # 60 GHz band channels 1-4, # ref: http://www.law.go.kr/%ED%96%89%EC%A0%95%EA%B7%9C%EC%B9%99/%EB%AC%B4%EC%84%A0%EC%84%A4%EB%B9%84%EA%B7%9C%EC%B9%99 @@ -967,12 +968,12 @@ country MT: DFS-ETSI # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR -country MU: DFS-FCC +country MU: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country MV: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1073,9 +1074,10 @@ country OM: DFS-ETSI country PA: (2402 - 2472 @ 40), (36) - (5170 - 5250 @ 80), (23), AUT0-BW - (5250 - 5330 @ 80), (30), AUTO-BW - (5735 - 5835 @ 80), (36) + (5170 - 5250 @ 80), (30), AUT0-BW + (5250 - 5330 @ 80), (24), AUTO-BW + (5490 - 5730 @ 160), (24), + (5735 - 5835 @ 80), (30) country PE: DFS-FCC (2402 - 2482 @ 40), (20) @@ -1169,9 +1171,12 @@ country PY: DFS-FCC (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) -country QA: +country QA: DFS-ETSI (2402 - 2482 @ 40), (20) - (5735 - 5835 @ 80), (30) + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5490 - 5730 @ 160), (20), DFS + (5735 - 5875 @ 80), (20) country RE: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1369,10 +1374,10 @@ country TZ: # disputable definitions there. country UA: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW - (5490 - 5670 @ 160), (20), DFS - (5735 - 5835 @ 80), (20) + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5490 - 5710 @ 160), (24), DFS + (5735 - 5835 @ 80), (24) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR From 62edbd4098fe6062435214b4c9f2821b78dd8e9e Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Thu, 5 Jul 2018 12:58:09 +0530 Subject: [PATCH 050/392] ARM: dts: msm: Add support for external codec on apq8009 Add support to enable wcd9326 codec on apq8009. CRs-Fixed: 2273335 Change-Id: I09243621d20ddefe39a0ab66a86d2e5405d5723b Signed-off-by: Dhanalakshmi Siddani --- arch/arm/boot/dts/qcom/apq8009-dragon.dtsi | 46 ++++++++++++++++++---- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/arch/arm/boot/dts/qcom/apq8009-dragon.dtsi b/arch/arm/boot/dts/qcom/apq8009-dragon.dtsi index 810b6ae7d0f6..f651fa2c0c6c 100644 --- a/arch/arm/boot/dts/qcom/apq8009-dragon.dtsi +++ b/arch/arm/boot/dts/qcom/apq8009-dragon.dtsi @@ -17,9 +17,14 @@ #include "msm8909-pm8916-mtp.dtsi" #include "apq8009-audio-external_codec.dtsi" +&audio_codec_mtp { + status = "disabled"; +}; + &soc { - ext-codec { - qcom,msm-mbhc-hphl-swh = <0>; + sound-9335 { + qcom,model = "apq8009-tashalite-snd-card-tdm"; + qcom,tdm-i2s-switch-enable = <&msm_gpio 88 0>; qcom,audio-routing = "AIF4 VI", "MCLK", "RX_BIAS", "MCLK", @@ -38,16 +43,32 @@ "SpkrRight IN", "SPK2 OUT"; }; - sound-9335 { - status = "disabled"; - }; - i2c@78b8000 { wcd9xxx_codec@d { - status = "disabled"; + qcom,wcd9xxx-mic-tristate; + qcom,cdc-reset-gpio = <&msm_gpio 23 0>; + + cdc-vdd-buck-supply = <&wcd_vdd_buck_1p8>; + qcom,cdc-vdd-buck-voltage = <0 0>; + qcom,cdc-vdd-buck-current = <250000>; + + cdc-buck-sido-supply = <&wcd_vdd_buck_1p8>; + qcom,cdc-buck-sido-voltage = <0 0>; + qcom,cdc-buck-sido-current = <250000>; }; }; + wcd_vdd_buck_1p8: wcd_vdd_buck_1p8 { + compatible = "regulator-fixed"; + regulator-name = "wcd_vdd_buck_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + status = "ok"; + enable-active-high; + gpio = <&pm8916_gpios 4 0>; + vin-supply = <&pm8916_s4>; + }; + vph_pwr_vreg: vph_pwr_vreg { compatible = "regulator-fixed"; status = "ok"; @@ -128,6 +149,17 @@ }; }; +&pm8916_gpios { + gpio@c300 { + qcom,mode = <1>; /* DIGITAL OUT */ + qcom,pull = <1>; /* No Pull */ + qcom,vin-sel = <2>; /* 1.8 */ + qcom,src-sel = <0>; /* CONSTANT */ + qcom,master-en = <1>; /* ENABLE GPIO */ + status = "okay"; + }; +}; + &pm8916_bms { status = "ok"; qcom,disable-bms; From e0f9f55c34d0a2b225a3c828d1dfade10acaec68 Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Tue, 3 Jul 2018 15:58:47 +0530 Subject: [PATCH 051/392] defconfig: msm8909: Enable config flags for req-crypt These flag cater to full disk encryption support on top of HW crypto. Change-Id: I2aae4c2a6d45652c589fc7679860d85d6f0fdd33 Signed-off-by: Neeraj Soni --- arch/arm/configs/msm8909-perf_defconfig | 3 ++- arch/arm/configs/msm8909_defconfig | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 1526257a8889..6ad6a12bf530 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -256,6 +256,7 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y @@ -527,10 +528,10 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 68ef75ef979d..37f99e74abbd 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -261,6 +261,7 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y @@ -580,7 +581,6 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y From 97a8d29b2405036762fec02c1d957098be220cb8 Mon Sep 17 00:00:00 2001 From: Yu Wang Date: Tue, 26 Dec 2017 14:43:21 +0800 Subject: [PATCH 052/392] cnss: notify wlan driver when failed to power up During SSR, if power-up fails, wlan driver will enter ssr_in_progress state, which will block driver unloading, it's not reasonable. To improve this, notify wlan driver about the failure, then driver unloading can be handled properly according to this flag. Change-Id: I669cc0137811a991c00ff9e73ebbb2bcf2d621a1 Signed-off-by: Yu Wang CRs-Fixed: 2202980 --- drivers/net/wireless/cnss/cnss_pci.c | 12 ++++++++---- include/net/cnss.h | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index 0fb6d9c3143c..b13d62eae1a7 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -2731,10 +2731,14 @@ static int cnss_powerup(const struct subsys_desc *subsys) cnss_configure_wlan_en_gpio(WLAN_EN_LOW); cnss_wlan_vreg_set(vreg_info, VREG_OFF); if (penv->pdev) { - pr_err("%d: Unregistering pci device\n", __LINE__); - pci_unregister_driver(&cnss_wlan_pci_driver); - penv->pdev = NULL; - penv->pci_register_again = true; + if (wdrv && wdrv->update_status) + wdrv->update_status(penv->pdev, CNSS_WLAN_SSR_FAIL); + if (!penv->recovery_in_progress) { + pr_err("%d: Unregistering pci device\n", __LINE__); + pci_unregister_driver(&cnss_wlan_pci_driver); + penv->pdev = NULL; + penv->pci_register_again = true; + } } err_wlan_vreg_on: diff --git a/include/net/cnss.h b/include/net/cnss.h index 03b76ee9f38d..0ed190866103 100644 --- a/include/net/cnss.h +++ b/include/net/cnss.h @@ -37,6 +37,11 @@ enum cnss_cc_src { CNSS_SOURCE_USER }; +enum cnss_wlan_status { + CNSS_WLAN_LINK_DOWN, + CNSS_WLAN_SSR_FAIL +}; + /* FW image files */ struct cnss_fw_files { char image_file[CNSS_MAX_FILE_NAME]; From 0c8e1924f0cf2d2b1180d675c1a01afdc930e85d Mon Sep 17 00:00:00 2001 From: Yu Wang Date: Fri, 15 Jun 2018 15:25:33 +0800 Subject: [PATCH 053/392] cnss: merge cnss_wlan_status and cnss_driver_status In current cnss platform driver, there are 2 enumerations stand for wlan status: cnss_wlan_status and cnss_driver_status; while in cnss2, there is only 1: cnss_driver_status. It will lead to mismatch when co-working with the same wlan driver. To fix this problem, merge the 2 definitions, make these 2 platform drivers aligned. CRs-Fixed: 2202980 Change-Id: If398597e54d55a6fa4a2553e48cc16f0a9f7340d Signed-off-by: Yu Wang --- drivers/net/wireless/cnss/cnss_pci.c | 4 ++-- include/net/cnss.h | 14 ++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index b13d62eae1a7..66508279caff 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2732,7 +2732,7 @@ static int cnss_powerup(const struct subsys_desc *subsys) cnss_wlan_vreg_set(vreg_info, VREG_OFF); if (penv->pdev) { if (wdrv && wdrv->update_status) - wdrv->update_status(penv->pdev, CNSS_WLAN_SSR_FAIL); + wdrv->update_status(penv->pdev, CNSS_SSR_FAIL); if (!penv->recovery_in_progress) { pr_err("%d: Unregistering pci device\n", __LINE__); pci_unregister_driver(&cnss_wlan_pci_driver); diff --git a/include/net/cnss.h b/include/net/cnss.h index 0ed190866103..c7f41e343c22 100644 --- a/include/net/cnss.h +++ b/include/net/cnss.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,11 +37,6 @@ enum cnss_cc_src { CNSS_SOURCE_USER }; -enum cnss_wlan_status { - CNSS_WLAN_LINK_DOWN, - CNSS_WLAN_SSR_FAIL -}; - /* FW image files */ struct cnss_fw_files { char image_file[CNSS_MAX_FILE_NAME]; @@ -107,11 +102,14 @@ struct cnss_platform_cap { u32 cap_flag; }; -/* WLAN driver status */ +/* WLAN driver status, keep it aligned with cnss2 */ enum cnss_driver_status { CNSS_UNINITIALIZED, CNSS_INITIALIZED, - CNSS_LOAD_UNLOAD + CNSS_LOAD_UNLOAD, + CNSS_RECOVERY, + CNSS_FW_DOWN, + CNSS_SSR_FAIL, }; enum cnss_runtime_request { From 2625339ef9c4a1517ca5da4d28420d8e09d47b38 Mon Sep 17 00:00:00 2001 From: Vijay Navnath Kamble Date: Tue, 10 Jul 2018 09:30:02 +0530 Subject: [PATCH 054/392] input: touchscreen: Remove himax touchscreen support Himax updated touch driver by fixing all the errors. Need to remove existing touch driver code and update with latest comits. Change-Id: I1e4d92ac59d872569df465f773323f336b796df9 Signed-off-by: Vijay Navnath Kamble --- .../bindings/input/touchscreen/himax.txt | 22 - .../bindings/input/touchscreen/hmxchipset.txt | 47 - arch/arm/configs/msmcortex-perf_defconfig | 4 - arch/arm/configs/msmcortex_defconfig | 4 - drivers/input/touchscreen/Kconfig | 12 - drivers/input/touchscreen/Makefile | 1 - .../hxchipset/HX83100_Amber_0901_030B.i | 0 .../input/touchscreen/hxchipset/HX_CRC_124.i | 0 .../input/touchscreen/hxchipset/HX_CRC_128.i | 0 .../input/touchscreen/hxchipset/HX_CRC_60.i | 0 .../input/touchscreen/hxchipset/HX_CRC_64.i | 0 drivers/input/touchscreen/hxchipset/Kconfig | 21 - drivers/input/touchscreen/hxchipset/Makefile | 3 - .../touchscreen/hxchipset/himax_common.c | 1936 -------------- .../touchscreen/hxchipset/himax_common.h | 395 --- .../input/touchscreen/hxchipset/himax_debug.c | 2329 ----------------- .../input/touchscreen/hxchipset/himax_debug.h | 181 -- .../input/touchscreen/hxchipset/himax_ic.c | 2118 --------------- .../input/touchscreen/hxchipset/himax_ic.h | 82 - .../touchscreen/hxchipset/himax_platform.c | 796 ------ .../touchscreen/hxchipset/himax_platform.h | 135 - 21 files changed, 8086 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/himax.txt delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/hmxchipset.txt delete mode 100644 drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i delete mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_124.i delete mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_128.i delete mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_60.i delete mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_64.i delete mode 100644 drivers/input/touchscreen/hxchipset/Kconfig delete mode 100644 drivers/input/touchscreen/hxchipset/Makefile delete mode 100644 drivers/input/touchscreen/hxchipset/himax_common.c delete mode 100644 drivers/input/touchscreen/hxchipset/himax_common.h delete mode 100644 drivers/input/touchscreen/hxchipset/himax_debug.c delete mode 100644 drivers/input/touchscreen/hxchipset/himax_debug.h delete mode 100644 drivers/input/touchscreen/hxchipset/himax_ic.c delete mode 100644 drivers/input/touchscreen/hxchipset/himax_ic.h delete mode 100644 drivers/input/touchscreen/hxchipset/himax_platform.c delete mode 100644 drivers/input/touchscreen/hxchipset/himax_platform.h diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax.txt b/Documentation/devicetree/bindings/input/touchscreen/himax.txt deleted file mode 100644 index b54c85971927..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/himax.txt +++ /dev/null @@ -1,22 +0,0 @@ -Himax touch controller - -Required properties: - - - compatible : Should be "himax,hxcommon" - - reg : i2c slave address of the device. - - interrupt-parent : parent of interrupt. - - himax,irq-gpio : irq gpio. - - himax,reset-gpio : reset gpio. - - vdd-supply : Power supply needed to power up the device. - - avdd-supply : Power source required to power up i2c bus. - - himax,panel-coords : panel coordinates for the chip in pixels. - It is a four tuple consisting of min x, - min y, max x and max y values. - - himax,display-coords : display coordinates in pixels. It is a four - tuple consisting of min x, min y, max x and - max y values - -Optional properties: - - himax,3v3-gpio : gpio acting as 3.3 v supply. - - report_type : Multi-touch protocol type. Default 0. - 0 for protocol A, 1 for protocol B. diff --git a/Documentation/devicetree/bindings/input/touchscreen/hmxchipset.txt b/Documentation/devicetree/bindings/input/touchscreen/hmxchipset.txt deleted file mode 100644 index b1fc17fff80f..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/hmxchipset.txt +++ /dev/null @@ -1,47 +0,0 @@ -Himax Touch Controller - -Required properties: - - - compatible : Should be "himax,hxcommon" - - reg : I2C slave address of the device. - - interrupt-parent : Parent of interrupt. - - interrupts : Configuration of touch panel controller interrupt - GPIO. - - interrupt-gpios : Interrupt gpio which is to provide interrupts to - host, same as "interrupts" node. - - reset-gpios : Reset gpio to control the reset of chip. - - himax,display-coords : Display coordinates in pixels. It is a four - tuple consisting of min x, min y, max x and - max y values. - -Optional properties: - - - avdd-supply : Power supply needed to power up the device, this is - for fixed voltage external regulator. - - vdd-supply : Power supply needed to power up the device, when use - external regulator, do not add this property. - - himax,panel-coords : Panel coordinates for the chip in pixels. - It is a four tuple consisting of min x, - min y, max x and max y values. - -Example: -&i2c_3 { - status = "okay"; - himax_ts@48 { - compatible = "himax,hxcommon"; - reg = <0x48>; - interrupt-parent = <&tlmm>; - interrupts = <65 0x2>; - vdd-supply = <&pm8953_l10>; - avdd-supply = <&pm8953_l5>; - pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_release"; - pinctrl-0 = <&ts_int_active &ts_reset_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - pinctrl-2 = <&ts_release>; - himax,panel-coords = <0 800 0 1280>; - himax,display-coords = <0 800 0 1280>; - himax,irq-gpio = <&tlmm 65 0x2008>; - //himax,rst-gpio = <&tlmm 64 0x0>; - report_type = <1>; - }; -}; diff --git a/arch/arm/configs/msmcortex-perf_defconfig b/arch/arm/configs/msmcortex-perf_defconfig index 378119e357a0..0152945efdc6 100644 --- a/arch/arm/configs/msmcortex-perf_defconfig +++ b/arch/arm/configs/msmcortex-perf_defconfig @@ -307,10 +307,6 @@ CONFIG_TOUCHSCREEN_ATMEL_MXT=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_MAXIM_STI=y -CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y -CONFIG_TOUCHSCREEN_HIMAX_I2C=y -CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y -CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_KEYCHORD=y diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig index 4e6b91757b5f..cb620619749a 100644 --- a/arch/arm/configs/msmcortex_defconfig +++ b/arch/arm/configs/msmcortex_defconfig @@ -307,10 +307,6 @@ CONFIG_SECURE_TOUCH=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_MAXIM_STI=y -CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y -CONFIG_TOUCHSCREEN_HIMAX_I2C=y -CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y -CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_UINPUT=y diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 769849d2e43c..dd9b928e3694 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1137,16 +1137,4 @@ config TOUCHSCREEN_MAXIM_STI source "drivers/input/touchscreen/gt9xx/Kconfig" -config TOUCHSCREEN_HIMAX_CHIPSET - bool "Himax touchpanel CHIPSET" - depends on I2C - help - Say Y here if you have a Himax CHIPSET touchscreen. - HIMAX controllers are multi touch controllers which can - report 10 touches at a time. - - If unsure, say N. - -source "drivers/input/touchscreen/hxchipset/Kconfig" - endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 499b8110fe6c..be0eb9b34f5b 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -90,4 +90,3 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV) += synaptics_rmi_dev.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_fw_update.o obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/ -obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ diff --git a/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i b/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_124.i b/drivers/input/touchscreen/hxchipset/HX_CRC_124.i deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_128.i b/drivers/input/touchscreen/hxchipset/HX_CRC_128.i deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_60.i b/drivers/input/touchscreen/hxchipset/HX_CRC_60.i deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_64.i b/drivers/input/touchscreen/hxchipset/HX_CRC_64.i deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig deleted file mode 100644 index ebf3aa478af5..000000000000 --- a/drivers/input/touchscreen/hxchipset/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -# -# Himax Touchscreen driver configuration -# - -config TOUCHSCREEN_HIMAX_I2C - tristate "HIMAX chipset i2c touchscreen" - depends on TOUCHSCREEN_HIMAX_CHIPSET - help - This enables support for HIMAX CHIPSET over I2C based touchscreens. - -config TOUCHSCREEN_HIMAX_DEBUG - tristate "HIMAX debug function" - depends on TOUCHSCREEN_HIMAX_I2C - help - This enables support for HIMAX debug function. - -config HMX_DB - tristate "HIMAX driver test over Dragon Board" - depends on TOUCHSCREEN_HIMAX_I2C - help - This enables support for HIMAX driver test over Dragon Board. diff --git a/drivers/input/touchscreen/hxchipset/Makefile b/drivers/input/touchscreen/hxchipset/Makefile deleted file mode 100644 index 509d4913bc39..000000000000 --- a/drivers/input/touchscreen/hxchipset/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# Makefile for the Himax touchscreen drivers. - -obj-$(CONFIG_TOUCHSCREEN_HIMAX_I2C) += himax_platform.o himax_ic.o himax_common.o himax_debug.o diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c deleted file mode 100644 index 417b0c08e361..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_common.c +++ /dev/null @@ -1,1936 +0,0 @@ -/* Himax Android Driver Sample Code for Himax chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_common.h" -#include "himax_ic.h" - -#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F -#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) -#define FRAME_COUNT 5 - -#if defined(HX_AUTO_UPDATE_FW) - static unsigned char i_CTPM_FW[]= - { - #include "HX83100_Amber_0901_030B.i" - }; -#endif - -#ifdef HX_ESD_WORKAROUND - extern void HX_report_ESD_event(void); - unsigned char ESD_00_counter = 0; - unsigned char ESD_00_Flag = 0; -#endif - -//static int tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; // for Virtual key array - -struct himax_ts_data *private_ts; -struct himax_ic_data* ic_data; - -static int HX_TOUCH_INFO_POINT_CNT; - -#ifdef HX_AUTO_UPDATE_FW -extern unsigned long FW_VER_MAJ_FLASH_ADDR; -extern unsigned long FW_VER_MIN_FLASH_ADDR; -extern unsigned long CFG_VER_MAJ_FLASH_ADDR; -extern unsigned long CFG_VER_MIN_FLASH_ADDR; -#endif -extern unsigned long FW_VER_MAJ_FLASH_LENG; -extern unsigned long FW_VER_MIN_FLASH_LENG; -extern unsigned long CFG_VER_MAJ_FLASH_LENG; -extern unsigned long CFG_VER_MIN_FLASH_LENG; -extern unsigned char IC_TYPE; -extern unsigned char IC_CHECKSUM; - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) -extern int himax_touch_proc_init(void); -extern void himax_touch_proc_deinit(void); -//PROC-START -#ifdef HX_TP_PROC_FLASH_DUMP -extern void himax_ts_flash_func(void); -extern void setFlashBuffer(void); -extern bool getFlashDumpGoing(void); -extern uint8_t getSysOperation(void); -extern void setSysOperation(uint8_t operation); -#endif - -#ifdef HX_TP_PROC_HITOUCH -extern bool hitouch_is_connect; -#endif - -#ifdef HX_TP_PROC_DIAG - extern int touch_monitor_stop_flag; - extern int touch_monitor_stop_limit; - extern void himax_ts_diag_func(void); - extern int16_t *getMutualBuffer(void); - extern int16_t *getMutualNewBuffer(void); - extern int16_t *getMutualOldBuffer(void); - extern int16_t *getSelfBuffer(void); - extern uint8_t getXChannel(void); - extern uint8_t getYChannel(void); - extern uint8_t getDiagCommand(void); - extern void setXChannel(uint8_t x); - extern void setYChannel(uint8_t y); - extern void setMutualBuffer(void); - extern void setMutualNewBuffer(void); - extern void setMutualOldBuffer(void); - extern uint8_t coordinate_dump_enable; - extern struct file *coordinate_fn; - extern uint8_t diag_coor[128]; -#ifdef HX_TP_PROC_2T2R - extern int16_t *getMutualBuffer_2(void); - extern uint8_t getXChannel_2(void); - extern uint8_t getYChannel_2(void); - extern void setXChannel_2(uint8_t x); - extern void setYChannel_2(uint8_t y); - extern void setMutualBuffer_2(void); -#endif -#endif -//PROC-END -#endif - -extern int himax_parse_dt(struct himax_ts_data *ts, - struct himax_i2c_platform_data *pdata); -extern int himax_ts_pinctrl_init(struct himax_ts_data *ts); - -static uint8_t vk_press; -static uint8_t AA_press; -static uint8_t EN_NoiseFilter; -static uint8_t Last_EN_NoiseFilter; -static int hx_point_num; // for himax_ts_work_func use -static int p_point_num = 0xFFFF; -static int tpd_key; -static int tpd_key_old; -static int probe_fail_flag; -static bool config_load; -static struct himax_config *config_selected; - -//static int iref_number = 11; -//static bool iref_found = false; - -#ifdef HX_USB_DETECT2 -extern bool USB_Flag; -#endif - -#if defined(CONFIG_FB) -int fb_notifier_callback(struct notifier_block *self, - unsigned long event, void *data); -#elif defined(CONFIG_HAS_EARLYSUSPEND) -static void himax_ts_early_suspend(struct early_suspend *h); -static void himax_ts_late_resume(struct early_suspend *h); -#endif - -int himax_input_register(struct himax_ts_data *ts) -{ - int ret; - ts->input_dev = input_allocate_device(); - if (ts->input_dev == NULL) { - ret = -ENOMEM; - E("%s: Failed to allocate input device\n", __func__); - return ret; - } - ts->input_dev->name = "himax-touchscreen"; - - set_bit(EV_SYN, ts->input_dev->evbit); - set_bit(EV_ABS, ts->input_dev->evbit); - set_bit(EV_KEY, ts->input_dev->evbit); - - set_bit(KEY_BACK, ts->input_dev->keybit); - set_bit(KEY_HOME, ts->input_dev->keybit); - set_bit(KEY_MENU, ts->input_dev->keybit); - set_bit(KEY_SEARCH, ts->input_dev->keybit); -#if defined(HX_SMART_WAKEUP) - set_bit(KEY_POWER, ts->input_dev->keybit); - set_bit(KEY_CUST_01, ts->input_dev->keybit); - set_bit(KEY_CUST_02, ts->input_dev->keybit); - set_bit(KEY_CUST_03, ts->input_dev->keybit); - set_bit(KEY_CUST_04, ts->input_dev->keybit); - set_bit(KEY_CUST_05, ts->input_dev->keybit); - set_bit(KEY_CUST_06, ts->input_dev->keybit); - set_bit(KEY_CUST_07, ts->input_dev->keybit); - set_bit(KEY_CUST_08, ts->input_dev->keybit); - set_bit(KEY_CUST_09, ts->input_dev->keybit); - set_bit(KEY_CUST_10, ts->input_dev->keybit); - set_bit(KEY_CUST_11, ts->input_dev->keybit); - set_bit(KEY_CUST_12, ts->input_dev->keybit); - set_bit(KEY_CUST_13, ts->input_dev->keybit); - set_bit(KEY_CUST_14, ts->input_dev->keybit); - set_bit(KEY_CUST_15, ts->input_dev->keybit); -#endif - set_bit(BTN_TOUCH, ts->input_dev->keybit); - - set_bit(KEY_F10, ts->input_dev->keybit); - - set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); - - if (ts->protocol_type == PROTOCOL_TYPE_A) { - //ts->input_dev->mtsize = ts->nFinger_support; - input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, - 0, 3, 0, 0); - } else {/* PROTOCOL_TYPE_B */ - set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); - input_mt_init_slots(ts->input_dev, ts->nFinger_support,0); - } - - I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n", - ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); - - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,ts->pdata->abs_width_min, ts->pdata->abs_width_max, ts->pdata->abs_pressure_fuzz, 0); - -// input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, ((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0); -// input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, (BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0); - - return input_register_device(ts->input_dev); -} - -static void calcDataSize(uint8_t finger_num) -{ - struct himax_ts_data *ts_data = private_ts; - ts_data->coord_data_size = 4 * finger_num; - ts_data->area_data_size = ((finger_num / 4) + (finger_num % 4 ? 1 : 0)) * 4; - ts_data->raw_data_frame_size = 128 - ts_data->coord_data_size - ts_data->area_data_size - 4 - 4 - 1; - ts_data->raw_data_nframes = ((uint32_t)ts_data->x_channel * ts_data->y_channel + - ts_data->x_channel + ts_data->y_channel) / ts_data->raw_data_frame_size + - (((uint32_t)ts_data->x_channel * ts_data->y_channel + - ts_data->x_channel + ts_data->y_channel) % ts_data->raw_data_frame_size)? 1 : 0; - I("%s: coord_data_size: %d, area_data_size:%d, raw_data_frame_size:%d, raw_data_nframes:%d", __func__, ts_data->coord_data_size, ts_data->area_data_size, ts_data->raw_data_frame_size, ts_data->raw_data_nframes); -} - -static void calculate_point_number(void) -{ - HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4 ; - - if ( (ic_data->HX_MAX_PT % 4) == 0) - HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4 ; - else - HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) +1) * 4 ; -} - -#if 0 -static int himax_read_Sensor_ID(struct i2c_client *client) -{ - uint8_t val_high[1], val_low[1], ID0=0, ID1=0; - char data[3]; - const int normalRetry = 10; - int sensor_id; - - data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - //read id pin high - i2c_himax_read(client, 0x57, val_high, 1, normalRetry); - - data[0] = 0x56; data[1] = 0x01; data[2] = 0x01;/*ID pin PULL Low*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - //read id pin low - i2c_himax_read(client, 0x57, val_low, 1, normalRetry); - - if((val_high[0] & 0x01) ==0) - ID0=0x02;/*GND*/ - else if((val_low[0] & 0x01) ==0) - ID0=0x01;/*Floating*/ - else - ID0=0x04;/*VCC*/ - - if((val_high[0] & 0x02) ==0) - ID1=0x02;/*GND*/ - else if((val_low[0] & 0x02) ==0) - ID1=0x01;/*Floating*/ - else - ID1=0x04;/*VCC*/ - if((ID0==0x04)&&(ID1!=0x04)) - { - data[0] = 0x56; data[1] = 0x02; data[2] = 0x01;/*ID pin PULL High,Low*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - } - else if((ID0!=0x04)&&(ID1==0x04)) - { - data[0] = 0x56; data[1] = 0x01; data[2] = 0x02;/*ID pin PULL Low,High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - } - else if((ID0==0x04)&&(ID1==0x04)) - { - data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High,High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - } - sensor_id=(ID1<<4)|ID0; - - data[0] = 0xE4; data[1] = sensor_id; - i2c_himax_master_write(client, &data[0],2,normalRetry);/*Write to MCU*/ - usleep_range(1000, 2000); - - return sensor_id; - -} -#endif -static void himax_power_on_initCMD(struct i2c_client *client) -{ - I("%s:\n", __func__); - - himax_touch_information(client); - - //himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM -} - -#ifdef HX_AUTO_UPDATE_FW -static int i_update_FW(void) -{ - int upgrade_times = 0; - unsigned char* ImageBuffer = i_CTPM_FW; - int fullFileLength = sizeof(i_CTPM_FW); - int i_FW_VER = 0, i_CFG_VER = 0; - uint8_t ret = -1, result = 0; -// uint8_t tmp_addr[4]; -// uint8_t tmp_data[4]; - int CRC_from_FW = 0; - int CRC_Check_result = 0; - - i_FW_VER = i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[FW_VER_MIN_FLASH_ADDR]; - i_CFG_VER = i_CTPM_FW[CFG_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[CFG_VER_MIN_FLASH_ADDR]; - - I("%s: i_fullFileLength = %d\n", __func__,fullFileLength); - - himax_sense_off(private_ts->client); - msleep(500); - - CRC_from_FW = himax_check_CRC(private_ts->client,fw_image_64k); - CRC_Check_result = Calculate_CRC_with_AP(ImageBuffer, CRC_from_FW,fw_image_64k); - I("%s: Check sum result = %d\n", __func__,CRC_Check_result); - //I("%s: ic_data->vendor_fw_ver = %X, i_FW_VER = %X,\n", __func__,ic_data->vendor_fw_ver, i_FW_VER); - //I("%s: ic_data->vendor_config_ver = %X, i_CFG_VER = %X,\n", __func__,ic_data->vendor_config_ver, i_CFG_VER); - - if ((CRC_Check_result == 0)|| ( ic_data->vendor_fw_ver < i_FW_VER ) || ( ic_data->vendor_config_ver < i_CFG_VER )) - { - himax_int_enable(private_ts->client->irq,0); -update_retry: - if(fullFileLength == FW_SIZE_60k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_64k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_124k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_128k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,ImageBuffer,fullFileLength,false); - } - if(ret == 0){ - upgrade_times++; - E("%s: TP upgrade error, upgrade_times = %d\n", __func__, upgrade_times); - if(upgrade_times < 3) - goto update_retry; - else - { - himax_sense_on(private_ts->client, 0x01); - msleep(120); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - result = -1;//upgrade fail - } - } - else if(ret == 1){ -/* - // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); - - // 2. Write driver initial code condition - // write value from AHB I2C : 0x8001_C603 = 0x000000FF - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xC6; tmp_addr[0] = 0x03; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xFF; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); - - // 1. Set DDREG_Req = 0 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); -*/ - himax_sense_on(private_ts->client, 0x01); - msleep(120); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - - ic_data->vendor_fw_ver = i_FW_VER; - ic_data->vendor_config_ver = i_CFG_VER; - result = 1;//upgrade success - I("%s: TP upgrade OK\n", __func__); - } - - himax_int_enable(private_ts->client->irq,1); - return result; - } - else - { - himax_sense_on(private_ts->client, 0x01); - return 0;//NO upgrade - } -} -#endif - -#ifdef HX_RST_PIN_FUNC -void himax_HW_reset(uint8_t loadconfig,uint8_t int_off) -{ - struct himax_ts_data *ts = private_ts; - int ret = 0; - - return; - if (ts->rst_gpio) { - if(int_off) - { - if (ts->use_irq) - himax_int_enable(private_ts->client->irq,0); - else { - hrtimer_cancel(&ts->timer); - ret = cancel_work_sync(&ts->work); - } - } - - I("%s: Now reset the Touch chip.\n", __func__); - - himax_rst_gpio_set(ts->rst_gpio, 0); - msleep(20); - himax_rst_gpio_set(ts->rst_gpio, 1); - msleep(20); - - if(loadconfig) - himax_loadSensorConfig(private_ts->client,private_ts->pdata); - - if(int_off) - { - if (ts->use_irq) - himax_int_enable(private_ts->client->irq,1); - else - hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); - } - } -} -#endif - -int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata) -{ - - if (!client) { - E("%s: Necessary parameters client are null!\n", __func__); - return -EINVAL; - } - - if(config_load == false) - { - config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); - if (config_selected == NULL) { - E("%s: alloc config_selected fail!\n", __func__); - return -ENOMEM; - } - } - - himax_power_on_initCMD(client); - - himax_int_enable(client->irq,0); - himax_read_FW_ver(client); -#ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); -#endif - himax_int_enable(client->irq,1); - I("FW_VER : %X \n",ic_data->vendor_fw_ver); - - ic_data->vendor_sensor_id=0x2602; - I("sensor_id=%x.\n",ic_data->vendor_sensor_id); - - himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM - msleep(120); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - I("%s: initialization complete\n", __func__); - - return 1; -} - -#ifdef HX_ESD_WORKAROUND -void ESD_HW_REST(void) -{ - I("START_Himax TP: ESD - Reset\n"); - - HX_report_ESD_event(); - ESD_00_counter = 0; - ESD_00_Flag = 0; - /*************************************/ - if (private_ts->protocol_type == PROTOCOL_TYPE_A) - input_mt_sync(private_ts->input_dev); - input_report_key(private_ts->input_dev, BTN_TOUCH, 0); - input_sync(private_ts->input_dev); - /*************************************/ - - I("END_Himax TP: ESD - Reset\n"); -} -#endif -#ifdef HX_HIGH_SENSE -void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable) -{ - uint8_t tmp_data[4]; - - if(HSEN_enable) - { - I(" %s in", __func__); - HSEN_bit_retry: - himax_set_HSEN_enable(client,HSEN_enable); - msleep(20); - himax_get_HSEN_enable(client,tmp_data); - I("%s: Read HSEN bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - if(tmp_data[0]!= 0x01) - { - I("%s: retry HSEN bit write data[0]=%x \n",__func__,tmp_data[0]); - goto HSEN_bit_retry; - } - } -} - -static void himax_HSEN_func(struct work_struct *work) -{ - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, - hsen_work.work); - - himax_set_HSEN_func(ts->client, ts->HSEN_enable); -} - -#endif - -#ifdef HX_SMART_WAKEUP -#ifdef HX_GESTURE_TRACK -static void gest_pt_log_coordinate(int rx, int tx) -{ - //driver report x y with range 0 - 255 , we scale it up to x/y pixel - gest_pt_x[gest_pt_cnt] = rx*(ic_data->HX_X_RES)/255; - gest_pt_y[gest_pt_cnt] = tx*(ic_data->HX_Y_RES)/255; -} -#endif -static int himax_parse_wake_event(struct himax_ts_data *ts) -{ - uint8_t buf[64]; - unsigned char check_sum_cal = 0; -#ifdef HX_GESTURE_TRACK - int tmp_max_x=0x00,tmp_min_x=0xFFFF,tmp_max_y=0x00,tmp_min_y=0xFFFF; - int gest_len; -#endif - int i=0, check_FC = 0, gesture_flag = 0; - - himax_burst_enable(ts->client, 0); - himax_read_event_stack(ts->client,buf,56); - - for(i=0;igest_pt_x[i]) - tmp_min_x=gest_pt_x[i]; - if(tmp_max_ygest_pt_y[i]) - tmp_min_y=gest_pt_y[i]; - } - I("gest_point x_min= %d, x_max= %d, y_min= %d, y_max= %d\n",tmp_min_x,tmp_max_x,tmp_min_y,tmp_max_y); - gest_start_x=gest_pt_x[0]; - gn_gesture_coor[0] = gest_start_x; - gest_start_y=gest_pt_y[0]; - gn_gesture_coor[1] = gest_start_y; - gest_end_x=gest_pt_x[gest_pt_cnt-1]; - gn_gesture_coor[2] = gest_end_x; - gest_end_y=gest_pt_y[gest_pt_cnt-1]; - gn_gesture_coor[3] = gest_end_y; - gest_width = tmp_max_x - tmp_min_x; - gn_gesture_coor[4] = gest_width; - gest_height = tmp_max_y - tmp_min_y; - gn_gesture_coor[5] = gest_height; - gest_mid_x = (tmp_max_x + tmp_min_x)/2; - gn_gesture_coor[6] = gest_mid_x; - gest_mid_y = (tmp_max_y + tmp_min_y)/2; - gn_gesture_coor[7] = gest_mid_y; - gn_gesture_coor[8] = gest_mid_x;//gest_up_x - gn_gesture_coor[9] = gest_mid_y-gest_height/2;//gest_up_y - gn_gesture_coor[10] = gest_mid_x;//gest_down_x - gn_gesture_coor[11] = gest_mid_y+gest_height/2; //gest_down_y - gn_gesture_coor[12] = gest_mid_x-gest_width/2; //gest_left_x - gn_gesture_coor[13] = gest_mid_y; //gest_left_y - gn_gesture_coor[14] = gest_mid_x+gest_width/2; //gest_right_x - gn_gesture_coor[15] = gest_mid_y; //gest_right_y - - } - - } -#endif - if(gesture_flag != 0x80) - { - if(!ts->gesture_cust_en[gesture_flag]) - { - I("%s NOT report customer key \n ",__func__); - return 0;//NOT report customer key - } - } - else - { - if(!ts->gesture_cust_en[0]) - { - I("%s NOT report report double click \n",__func__); - return 0;//NOT report power key - } - } - - if(gesture_flag == 0x80) - return EV_GESTURE_PWR; - else - return gesture_flag; -} - -void himax_wake_check_func(void) -{ - int ret_event = 0, KEY_EVENT = 0; - - ret_event = himax_parse_wake_event(private_ts); - switch (ret_event) { - case EV_GESTURE_PWR: - KEY_EVENT = KEY_POWER; - break; - case EV_GESTURE_01: - KEY_EVENT = KEY_CUST_01; - break; - case EV_GESTURE_02: - KEY_EVENT = KEY_CUST_02; - break; - case EV_GESTURE_03: - KEY_EVENT = KEY_CUST_03; - break; - case EV_GESTURE_04: - KEY_EVENT = KEY_CUST_04; - break; - case EV_GESTURE_05: - KEY_EVENT = KEY_CUST_05; - break; - case EV_GESTURE_06: - KEY_EVENT = KEY_CUST_06; - break; - case EV_GESTURE_07: - KEY_EVENT = KEY_CUST_07; - break; - case EV_GESTURE_08: - KEY_EVENT = KEY_CUST_08; - break; - case EV_GESTURE_09: - KEY_EVENT = KEY_CUST_09; - break; - case EV_GESTURE_10: - KEY_EVENT = KEY_CUST_10; - break; - case EV_GESTURE_11: - KEY_EVENT = KEY_CUST_11; - break; - case EV_GESTURE_12: - KEY_EVENT = KEY_CUST_12; - break; - case EV_GESTURE_13: - KEY_EVENT = KEY_CUST_13; - break; - case EV_GESTURE_14: - KEY_EVENT = KEY_CUST_14; - break; - case EV_GESTURE_15: - KEY_EVENT = KEY_CUST_15; - break; - } - if(ret_event) - { - I(" %s SMART WAKEUP KEY event %x press\n",__func__,KEY_EVENT); - input_report_key(private_ts->input_dev, KEY_EVENT, 1); - input_sync(private_ts->input_dev); - //msleep(100); - I(" %s SMART WAKEUP KEY event %x release\n",__func__,KEY_EVENT); - input_report_key(private_ts->input_dev, KEY_EVENT, 0); - input_sync(private_ts->input_dev); - FAKE_POWER_KEY_SEND=true; -#ifdef HX_GESTURE_TRACK - I("gest_start_x= %d, gest_start_y= %d, gest_end_x= %d, gest_end_y= %d\n",gest_start_x,gest_start_y, - gest_end_x,gest_end_y); - I("gest_width= %d, gest_height= %d, gest_mid_x= %d, gest_mid_y= %d\n",gest_width,gest_height, - gest_mid_x,gest_mid_y); - I("gest_up_x= %d, gest_up_y= %d, gest_down_x= %d, gest_down_y= %d\n",gn_gesture_coor[8],gn_gesture_coor[9], - gn_gesture_coor[10],gn_gesture_coor[11]); - I("gest_left_x= %d, gest_left_y= %d, gest_right_x= %d, gest_right_y= %d\n",gn_gesture_coor[12],gn_gesture_coor[13], - gn_gesture_coor[14],gn_gesture_coor[15]); -#endif - } -} - -#endif -static void himax_ts_button_func(int tp_key_index,struct himax_ts_data *ts) -{ - uint16_t x_position = 0, y_position = 0; -if ( tp_key_index != 0x00) - { - I("virtual key index =%x\n",tp_key_index); - if ( tp_key_index == 0x01) { - vk_press = 1; - I("back key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[0].index) { - x_position = (ts->button[0].x_range_min + ts->button[0].x_range_max) / 2; - y_position = (ts->button[0].y_range_min + ts->button[0].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } - } - else - input_report_key(ts->input_dev, KEY_BACK, 1); - } - else if ( tp_key_index == 0x02) { - vk_press = 1; - I("home key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[1].index) { - x_position = (ts->button[1].x_range_min + ts->button[1].x_range_max) / 2; - y_position = (ts->button[1].y_range_min + ts->button[1].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } - } - else - input_report_key(ts->input_dev, KEY_HOME, 1); - } - else if ( tp_key_index == 0x04) { - vk_press = 1; - I("APP_switch key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[2].index) { - x_position = (ts->button[2].x_range_min + ts->button[2].x_range_max) / 2; - y_position = (ts->button[2].y_range_min + ts->button[2].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } - } - else - input_report_key(ts->input_dev, KEY_F10, 1); - } - input_sync(ts->input_dev); - } -else/*tp_key_index =0x00*/ - { - I("virtual key released\n"); - vk_press = 0; - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_mt_sync(ts->input_dev); - } - else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); - } - input_report_key(ts->input_dev, KEY_BACK, 0); - input_report_key(ts->input_dev, KEY_HOME, 0); - input_report_key(ts->input_dev, KEY_F10, 0); - input_sync(ts->input_dev); - } -} - -void himax_ts_work(struct himax_ts_data *ts) -{ - int ret = 0; - uint8_t finger_num, hw_reset_check[2]; - uint8_t buf[128]; - uint8_t finger_on = 0; - int32_t loop_i; - uint16_t check_sum_cal = 0; - int raw_cnt_max ; - int raw_cnt_rmd ; - int hx_touch_info_size; - uint8_t coordInfoSize = ts->coord_data_size + ts->area_data_size + 4; - -#ifdef HX_TP_PROC_DIAG - int16_t *mutual_data; - int16_t *self_data; - uint8_t diag_cmd; - int i; - int mul_num; - int self_num; - int RawDataLen = 0; - //coordinate dump start - char coordinate_char[15+(ic_data->HX_MAX_PT+5)*2*5+2]; - //coordinate dump end -#endif - - memset(buf, 0x00, sizeof(buf)); - memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); - - raw_cnt_max = ic_data->HX_MAX_PT/4; - raw_cnt_rmd = ic_data->HX_MAX_PT%4; - -#if defined(HX_USB_DETECT2) - himax_cable_detect_func(); -#endif - - if (raw_cnt_rmd != 0x00) //more than 4 fingers - { - RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); - hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+2)*4; - } - else //less than 4 fingers - { - RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); - hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+1)*4; - } - -#ifdef HX_TP_PROC_DIAG - diag_cmd = getDiagCommand(); - if( diag_cmd ){ - ret = read_event_stack(ts->client, buf, 128); - } - else{ - if(touch_monitor_stop_flag != 0){ - ret = read_event_stack(ts->client, buf, 128); - touch_monitor_stop_flag-- ; - } - else{ - ret = read_event_stack(ts->client, buf, hx_touch_info_size); - } - } - - if (!ret) -#else - if(!read_event_stack(ts->client, buf, hx_touch_info_size)) -#endif - { - E("%s: can't read data from chip!\n", __func__); - goto err_workqueue_out; - } - post_read_event_stack(ts->client); -#ifdef HX_ESD_WORKAROUND - for(i = 0; i < hx_touch_info_size; i++) - { - if(buf[i] == 0xED)/*case 1 ESD recovery flow*/ - { - check_sum_cal = 1; - - }else if(buf[i] == 0x00) - { - ESD_00_Flag = 1; - } - else - { - check_sum_cal = 0; - ESD_00_counter = 0; - ESD_00_Flag = 0; - i = hx_touch_info_size; - break; - } - } - if (ESD_00_Flag == 1){ - ESD_00_counter ++; - } - if (ESD_00_counter > 1){ - check_sum_cal = 2; - } - - if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0) - { - I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); - ESD_HW_REST(); - return; - } - - if (check_sum_cal == 1 && HX_ESD_RESET_ACTIVATE == 0) - { - I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n"); - ESD_HW_REST(); - return; - } - else if (HX_ESD_RESET_ACTIVATE) - { -#ifdef HX_SMART_WAKEUP - queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(50)); -#endif -#ifdef HX_HIGH_SENSE - queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(50)); -#endif - HX_ESD_RESET_ACTIVATE = 0;/*drop 1st interrupts after chip reset*/ - I("[HIMAX TP MSG]:%s: Back from reset, ready to serve.\n", __func__); - } -#endif - for (loop_i = 0, check_sum_cal = 0; loop_i < hx_touch_info_size; loop_i++) - check_sum_cal += buf[loop_i]; - - if ((check_sum_cal % 0x100 != 0) ) - { - I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", check_sum_cal); - return; - } - - if (ts->debug_log_level & BIT(0)) { - I("%s: raw data:\n", __func__); - for (loop_i = 0; loop_i < hx_touch_info_size; loop_i++) { - I("P %d = 0x%2.2X ", loop_i, buf[loop_i]); - if (loop_i % 8 == 7) - I("\n"); - } - } - - //touch monitor raw data fetch -#ifdef HX_TP_PROC_DIAG - diag_cmd = getDiagCommand(); - if (diag_cmd >= 1 && diag_cmd <= 6) - { - //Check 124th byte CRC - if(!diag_check_sum(hx_touch_info_size, buf)) - { - goto bypass_checksum_failed_packet; - } -#ifdef HX_TP_PROC_2T2R - if(Is_2T2R && diag_cmd == 4) - { - mutual_data = getMutualBuffer_2(); - self_data = getSelfBuffer(); - - // initiallize the block number of mutual and self - mul_num = getXChannel_2() * getYChannel_2(); - -#ifdef HX_EN_SEL_BUTTON - self_num = getXChannel_2() + getYChannel_2() + ic_data->HX_BT_NUM; -#else - self_num = getXChannel_2() + getYChannel_2(); -#endif - } - else -#endif - { - mutual_data = getMutualBuffer(); - self_data = getSelfBuffer(); - - // initiallize the block number of mutual and self - mul_num = getXChannel() * getYChannel(); - -#ifdef HX_EN_SEL_BUTTON - self_num = getXChannel() + getYChannel() + ic_data->HX_BT_NUM; -#else - self_num = getXChannel() + getYChannel(); -#endif - } - - diag_parse_raw_data(hx_touch_info_size, RawDataLen, mul_num, self_num, buf, diag_cmd, mutual_data, self_data); - - } - else if (diag_cmd == 7) - { - memcpy(&(diag_coor[0]), &buf[0], 128); - } - //coordinate dump start - if (coordinate_dump_enable == 1) - { - for(i=0; i<(15 + (ic_data->HX_MAX_PT+5)*2*5); i++) - { - coordinate_char[i] = 0x20; - } - coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5] = 0xD; - coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5 + 1] = 0xA; - } - //coordinate dump end -bypass_checksum_failed_packet: -#endif - EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>3); - //I("EN_NoiseFilter=%d\n",EN_NoiseFilter); - EN_NoiseFilter = EN_NoiseFilter & 0x01; - //I("EN_NoiseFilter2=%d\n",EN_NoiseFilter); - -#if defined(HX_EN_SEL_BUTTON) || defined(HX_EN_MUT_BUTTON) - tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>4); - if (tpd_key == 0x0F)/*All (VK+AA)leave*/ - { - tpd_key = 0x00; - } - //I("[DEBUG] tpd_key: %x\r\n", tpd_key); -#else - tpd_key = 0x00; -#endif - - p_point_num = hx_point_num; - - if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) - hx_point_num = 0; - else - hx_point_num= buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; - - // Touch Point information - if (hx_point_num != 0 ) { - if(vk_press == 0x00) - { - uint16_t old_finger = ts->pre_finger_mask; - ts->pre_finger_mask = 0; - finger_num = buf[coordInfoSize - 4] & 0x0F; - finger_on = 1; - AA_press = 1; - for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { - int base = loop_i * 4; - int x = buf[base] << 8 | buf[base + 1]; - int y = (buf[base + 2] << 8 | buf[base + 3]); - int w = buf[(ts->nFinger_support * 4) + loop_i]; - if(x >= 0 && x <= ts->pdata->abs_x_max && y >= 0 && y <= ts->pdata->abs_y_max){ - finger_num--; - - if ((ts->debug_log_level & BIT(3)) > 0) - { - if (old_finger >> loop_i == 0) - { - if (ts->useScreenRes) - { - I("status: Screen:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", - loop_i+1, x * ts->widthFactor >> SHIFTBITS, - y * ts->heightFactor >> SHIFTBITS, w, EN_NoiseFilter); - } - else - { - I("status: Raw:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", - loop_i+1, x, y, w, EN_NoiseFilter); - } - } - } - - if (ts->protocol_type == PROTOCOL_TYPE_B) - { - input_mt_slot(ts->input_dev, loop_i); - } - - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, w); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); - - if (ts->protocol_type == PROTOCOL_TYPE_A) - { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, loop_i); - input_mt_sync(ts->input_dev); - } - else - { - ts->last_slot = loop_i; - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); - } - - if (!ts->first_pressed) - { - ts->first_pressed = 1; - I("S1@%d, %d\n", x, y); - } - - ts->pre_finger_data[loop_i][0] = x; - ts->pre_finger_data[loop_i][1] = y; - - - if (ts->debug_log_level & BIT(1)) - I("Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, N:%d\n", - loop_i + 1, x, y, w, w, loop_i + 1, EN_NoiseFilter); - - ts->pre_finger_mask = ts->pre_finger_mask + (1 << loop_i); - - } else { - if (ts->protocol_type == PROTOCOL_TYPE_B) - { - input_mt_slot(ts->input_dev, loop_i); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); - } - - if (loop_i == 0 && ts->first_pressed == 1) - { - ts->first_pressed = 2; - I("E1@%d, %d\n", - ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); - } - if ((ts->debug_log_level & BIT(3)) > 0) - { - if (old_finger >> loop_i == 1) - { - if (ts->useScreenRes) - { - I("status: Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", - loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, - ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); - } - else - { - I("status: Raw:F:%02d Up, X:%d, Y:%d, N:%d\n", - loop_i+1, ts->pre_finger_data[loop_i][0], - ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); - } - } - } - } - } - - }else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { - //temp_x[0] = 0xFFFF; - //temp_y[0] = 0xFFFF; - //temp_x[1] = 0xFFFF; - //temp_y[1] = 0xFFFF; - himax_ts_button_func(tpd_key,ts); - finger_on = 0; - } - input_report_key(ts->input_dev, BTN_TOUCH, finger_on); - input_sync(ts->input_dev); - } else if (hx_point_num == 0){ - if(AA_press) - { - // leave event - finger_on = 0; - AA_press = 0; - if (ts->protocol_type == PROTOCOL_TYPE_A) - input_mt_sync(ts->input_dev); - - for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { - if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { - if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, loop_i); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); - } - } - } - if (ts->pre_finger_mask > 0) { - for (loop_i = 0; loop_i < ts->nFinger_support && (ts->debug_log_level & BIT(3)) > 0; loop_i++) { - if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { - if (ts->useScreenRes) { - I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, - ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); - } else { - I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n",0, loop_i+1, ts->pre_finger_data[loop_i][0],ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); - } - } - } - ts->pre_finger_mask = 0; - } - - if (ts->first_pressed == 1) { - ts->first_pressed = 2; - I("E1@%d, %d\n",ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); - } - - if (ts->debug_log_level & BIT(1)) - I("All Finger leave\n"); - - } - else if (tpd_key != 0x00) { - himax_ts_button_func(tpd_key,ts); - finger_on = 1; - } - else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { - himax_ts_button_func(tpd_key,ts); - finger_on = 0; - } - input_report_key(ts->input_dev, BTN_TOUCH, finger_on); - input_sync(ts->input_dev); - } - tpd_key_old = tpd_key; - Last_EN_NoiseFilter = EN_NoiseFilter; - -workqueue_out: - return; - -err_workqueue_out: - I("%s: Now reset the Touch chip.\n", __func__); - -#ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); -#endif - - goto workqueue_out; -} -enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) -{ - struct himax_ts_data *ts; - - ts = container_of(timer, struct himax_ts_data, timer); - queue_work(ts->himax_wq, &ts->work); - hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); - return HRTIMER_NORESTART; -} - -#if defined(HX_USB_DETECT) -static void himax_cable_tp_status_handler_func(int connect_status) -{ - struct himax_ts_data *ts; - I("Touch: cable change to %d\n", connect_status); - ts = private_ts; - if (ts->cable_config) { - if (!atomic_read(&ts->suspend_mode)) { - if ((!!connect_status) != ts->usb_connected) { - if (!!connect_status) { - ts->cable_config[1] = 0x01; - ts->usb_connected = 0x01; - } else { - ts->cable_config[1] = 0x00; - ts->usb_connected = 0x00; - } - - i2c_himax_master_write(ts->client, ts->cable_config, - sizeof(ts->cable_config), HIMAX_I2C_RETRY_TIMES); - - I("%s: Cable status change: 0x%2.2X\n", __func__, ts->cable_config[1]); - } else - I("%s: Cable status is the same as previous one, ignore.\n", __func__); - } else { - if (connect_status) - ts->usb_connected = 0x01; - else - ts->usb_connected = 0x00; - I("%s: Cable status remembered: 0x%2.2X\n", __func__, ts->usb_connected); - } - } -} - -static struct t_cable_status_notifier himax_cable_status_handler = { - .name = "usb_tp_connected", - .func = himax_cable_tp_status_handler_func, -}; - -#endif - -#if defined(HX_USB_DETECT2) -void himax_cable_detect_func(void) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[128]; - struct himax_ts_data *ts; - u32 connect_status = 0; - - connect_status = USB_Flag;//upmu_is_chr_det(); - ts = private_ts; - //I("Touch: cable status=%d, cable_config=%p, usb_connected=%d \n", connect_status,ts->cable_config, ts->usb_connected); - if (ts->cable_config) { - if ((!!connect_status) != ts->usb_connected) { - //notify USB plug/unplug - // 0x9008_8060 ==> 0x0000_0000/0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x60; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; - - if (!!connect_status) { - tmp_data[0] = 0x01; - ts->usb_connected = 0x01; - } else { - tmp_data[0] = 0x00; - ts->usb_connected = 0x00; - } - - himax_flash_write_burst(ts->client, tmp_addr, tmp_data); - - I("%s: Cable status change: 0x%2.2X\n", __func__, ts->usb_connected); - } - //else - //I("%s: Cable status is the same as previous one, ignore.\n", __func__); - } -} -#endif - -#ifdef CONFIG_FB -int himax_fb_register(struct himax_ts_data *ts) -{ - int ret = 0; - - I(" %s in", __func__); - ts->fb_notif.notifier_call = fb_notifier_callback; - ret = fb_register_client(&ts->fb_notif); - if (ret) - E(" Unable to register fb_notifier: %d\n", ret); - - return ret; -} -#endif - -#ifdef HX_SMART_WAKEUP -void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable) -{ - uint8_t tmp_data[4]; - - if(SMWP_enable) - { - SMWP_bit_retry: - himax_set_SMWP_enable(client, SMWP_enable); - msleep(20); - himax_get_SMWP_enable(client,tmp_data); - I("%s: Read SMWP bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - if(tmp_data[0]!= 0x01) - { - I("%s: retry SMWP bit write data[0]=%x \n",__func__,tmp_data[0]); - goto SMWP_bit_retry; - } - } -} - -static void himax_SMWP_work(struct work_struct *work) -{ - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, - smwp_work.work); - I(" %s in", __func__); - - himax_set_SMWP_func(ts->client,ts->SMWP_enable); - -} -#endif - -#ifdef HX_TP_PROC_FLASH_DUMP -static void himax_ts_flash_work_func(struct work_struct *work) -{ - himax_ts_flash_func(); -} -#endif - -#ifdef HX_TP_PROC_DIAG -static void himax_ts_diag_work_func(struct work_struct *work) -{ - himax_ts_diag_func(); -} -#endif - -void himax_ts_init(struct himax_ts_data *ts) -{ - int ret = 0, err = 0; - struct himax_i2c_platform_data *pdata; - struct i2c_client *client; - - client = ts->client; - pdata = ts->pdata; - - I("%s: Start.\n", __func__); - - /* Set pinctrl in active state */ - if (ts->ts_pinctrl) { - ret = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_active); - if (ret < 0) { - E("Failed to set pin in active state %d",ret); - } - } - - himax_burst_enable(client, 0); - - //Get Himax IC Type / FW information / Calculate the point number - if (himax_check_chip_version(ts->client) == false) { - E("Himax chip doesn NOT EXIST"); - goto err_ic_package_failed; - } - if (himax_ic_package_check(ts->client) == false) { - E("Himax chip doesn NOT EXIST"); - goto err_ic_package_failed; - } - - if (pdata->virtual_key) - ts->button = pdata->virtual_key; -#ifdef HX_TP_PROC_FLASH_DUMP - ts->flash_wq = create_singlethread_workqueue("himax_flash_wq"); - if (!ts->flash_wq) - { - E("%s: create flash workqueue failed\n", __func__); - err = -ENOMEM; - goto err_create_wq_failed; - } - - INIT_WORK(&ts->flash_work, himax_ts_flash_work_func); - - setSysOperation(0); - setFlashBuffer(); -#endif - -#ifdef HX_TP_PROC_DIAG - ts->himax_diag_wq = create_singlethread_workqueue("himax_diag"); - if (!ts->himax_diag_wq) - { - E("%s: create diag workqueue failed\n", __func__); - err = -ENOMEM; - goto err_create_wq_failed; - } - INIT_DELAYED_WORK(&ts->himax_diag_delay_wrok, himax_ts_diag_work_func); -#endif - -himax_read_FW_ver(client); - -#ifdef HX_AUTO_UPDATE_FW - I(" %s in", __func__); - if(i_update_FW() == false) - I("NOT Have new FW=NOT UPDATE=\n"); - else - I("Have new FW=UPDATE=\n"); -#endif - - //Himax Power On and Load Config - if (himax_loadSensorConfig(client, pdata) < 0) { - E("%s: Load Sesnsor configuration failed, unload driver.\n", __func__); - goto err_detect_failed; - } - - calculate_point_number(); -#ifdef HX_TP_PROC_DIAG - setXChannel(ic_data->HX_RX_NUM); // X channel - setYChannel(ic_data->HX_TX_NUM); // Y channel - - setMutualBuffer(); - setMutualNewBuffer(); - setMutualOldBuffer(); - if (getMutualBuffer() == NULL) { - E("%s: mutual buffer allocate fail failed\n", __func__); - return; - } -#ifdef HX_TP_PROC_2T2R - if(Is_2T2R){ - setXChannel_2(ic_data->HX_RX_NUM_2); // X channel - setYChannel_2(ic_data->HX_TX_NUM_2); // Y channel - - setMutualBuffer_2(); - - if (getMutualBuffer_2() == NULL) { - E("%s: mutual buffer 2 allocate fail failed\n", __func__); - return; - } - } -#endif -#endif -#ifdef CONFIG_OF - ts->power = pdata->power; -#endif - ts->pdata = pdata; - - ts->x_channel = ic_data->HX_RX_NUM; - ts->y_channel = ic_data->HX_TX_NUM; - ts->nFinger_support = ic_data->HX_MAX_PT; - //calculate the i2c data size - calcDataSize(ts->nFinger_support); - I("%s: calcDataSize complete\n", __func__); -#ifdef CONFIG_OF - ts->pdata->abs_pressure_min = 0; - ts->pdata->abs_pressure_max = 200; - ts->pdata->abs_width_min = 0; - ts->pdata->abs_width_max = 200; - pdata->cable_config[0] = 0x90; - pdata->cable_config[1] = 0x00; -#endif - ts->suspended = false; -#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) - ts->usb_connected = 0x00; - ts->cable_config = pdata->cable_config; -#endif - ts->protocol_type = pdata->protocol_type; - I("%s: Use Protocol Type %c\n", __func__, - ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); - - ret = himax_input_register(ts); - if (ret) { - E("%s: Unable to register %s input device\n", - __func__, ts->input_dev->name); - goto err_input_register_device_failed; - } -#ifdef HX_SMART_WAKEUP - ts->SMWP_enable=0; - wake_lock_init(&ts->ts_SMWP_wake_lock, WAKE_LOCK_SUSPEND, HIMAX_common_NAME); - - ts->himax_smwp_wq = create_singlethread_workqueue("HMX_SMWP_WORK"); - if (!ts->himax_smwp_wq) { - E(" allocate himax_smwp_wq failed\n"); - err = -ENOMEM; - goto err_smwp_wq_failed; - } - INIT_DELAYED_WORK(&ts->smwp_work, himax_SMWP_work); -#endif -#ifdef HX_HIGH_SENSE - ts->HSEN_enable=0; - ts->himax_hsen_wq = create_singlethread_workqueue("HMX_HSEN_WORK"); - if (!ts->himax_hsen_wq) { - E(" allocate himax_hsen_wq failed\n"); - err = -ENOMEM; - goto err_hsen_wq_failed; - } - INIT_DELAYED_WORK(&ts->hsen_work, himax_HSEN_func); -#endif - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - himax_touch_proc_init(); -#endif - -#if defined(HX_USB_DETECT) - if (ts->cable_config) - cable_detect_register_notifier(&himax_cable_status_handler); -#endif - - err = himax_ts_register_interrupt(ts->client); - if (err) - goto err_register_interrupt_failed; - return; - -err_register_interrupt_failed: -#ifdef HX_HIGH_SENSE -err_hsen_wq_failed: -#endif -#ifdef HX_SMART_WAKEUP -err_smwp_wq_failed: - wake_lock_destroy(&ts->ts_SMWP_wake_lock); -#endif -err_input_register_device_failed: - input_free_device(ts->input_dev); -err_detect_failed: -#ifdef HX_TP_PROC_FLASH_DUMP -err_create_wq_failed: -#endif -err_ic_package_failed: - -return; -} - -int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - int err = 0; - struct himax_ts_data *ts; - struct himax_i2c_platform_data *pdata; - - //Check I2C functionality - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - E("%s: i2c check functionality error\n", __func__); - err = -ENODEV; - goto err_check_functionality_failed; - } - - ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL); - if (ts == NULL) { - E("%s: allocate himax_ts_data failed\n", __func__); - err = -ENOMEM; - goto err_alloc_data_failed; - } - - i2c_set_clientdata(client, ts); - ts->client = client; - ts->dev = &client->dev; - - pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); - if (pdata == NULL) { /*Allocate Platform data space*/ - err = -ENOMEM; - goto err_dt_platform_data_fail; - } - - ic_data = kzalloc(sizeof(*ic_data), GFP_KERNEL); - if (ic_data == NULL) { /*Allocate IC data space*/ - err = -ENOMEM; - goto err_dt_ic_data_fail; - } - -#ifdef CONFIG_OF - if (client->dev.of_node) { /*DeviceTree Init Platform_data*/ - err = himax_parse_dt(ts, pdata); - if (err < 0) { - I(" pdata is NULL for DT\n"); - goto err_alloc_dt_pdata_failed; - } - } -#endif - -#ifdef HX_RST_PIN_FUNC - ts->rst_gpio = pdata->gpio_reset; -#endif - -himax_gpio_power_config(ts->client, pdata); - - err = himax_ts_pinctrl_init(ts); - if (err || ts->ts_pinctrl == NULL) { - E(" Pinctrl init failed\n"); - } - -#ifndef CONFIG_OF - if (pdata->power) { - err = pdata->power(1); - if (err < 0) { - E("%s: power on failed\n", __func__); - goto err_power_failed; - } - } -#endif - ts->pdata = pdata; - private_ts = ts; - - mutex_init(&ts->fb_mutex); - /* ts initialization is deferred till FB_UNBLACK event; - * probe is considered pending till then.*/ - ts->probe_done = false; -#ifdef CONFIG_FB - err = himax_fb_register(ts); - if (err) { - E("Falied to register fb notifier\n"); - err = -ENOMEM; - goto err_fb_notif_wq_create; - } -#endif - - return 0; - -#ifdef CONFIG_FB -err_fb_notif_wq_create: -#endif -#ifdef CONFIG_OF -err_alloc_dt_pdata_failed: -#else -err_power_failed: -err_get_platform_data_fail: -#endif - if (ts->ts_pinctrl) { - if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { - devm_pinctrl_put(ts->ts_pinctrl); - ts->ts_pinctrl = NULL; - } else { - err = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_release); - if (err) - E("failed to select relase pinctrl state %d\n", - err); - } - } - kfree(ic_data); - -err_dt_ic_data_fail: - kfree(pdata); - -err_dt_platform_data_fail: - kfree(ts); - -err_alloc_data_failed: - -err_check_functionality_failed: - probe_fail_flag = 1; - return err; - -} - -int himax_chip_common_remove(struct i2c_client *client) -{ - struct himax_ts_data *ts = i2c_get_clientdata(client); - int ret; -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - himax_touch_proc_deinit(); -#endif -#ifdef CONFIG_FB - if (fb_unregister_client(&ts->fb_notif)) - dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n"); -#endif - - if (!ts->use_irq) - hrtimer_cancel(&ts->timer); - - destroy_workqueue(ts->himax_wq); - - if (ts->protocol_type == PROTOCOL_TYPE_B) - input_mt_destroy_slots(ts->input_dev); - - input_unregister_device(ts->input_dev); - - if (ts->ts_pinctrl) { - if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { - devm_pinctrl_put(ts->ts_pinctrl); - ts->ts_pinctrl = NULL; - } else { - ret = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_release); - if (ret) - E("failed to select relase pinctrl state %d\n", - ret); - } - } -#ifdef HX_SMART_WAKEUP - wake_lock_destroy(&ts->ts_SMWP_wake_lock); -#endif - kfree(ts); - - return 0; - -} - -int himax_chip_common_suspend(struct himax_ts_data *ts) -{ - int ret; - - if(ts->suspended) - { - I("%s: Already suspended. Skipped. \n", __func__); - return 0; - } - else - { - ts->suspended = true; - I("%s: enter \n", __func__); - } - -#ifdef HX_TP_PROC_FLASH_DUMP - if (getFlashDumpGoing()) - { - I("[himax] %s: Flash dump is going, reject suspend\n",__func__); - return 0; - } -#endif -#ifdef HX_TP_PROC_HITOUCH - if(hitouch_is_connect) - { - I("[himax] %s: Hitouch connect, reject suspend\n",__func__); - return 0; - } -#endif -#ifdef HX_SMART_WAKEUP - if(ts->SMWP_enable) - { - atomic_set(&ts->suspend_mode, 1); - ts->pre_finger_mask = 0; - FAKE_POWER_KEY_SEND=false; - I("[himax] %s: SMART_WAKEUP enable, reject suspend\n",__func__); - return 0; - } -#endif -#ifdef HX_ESD_WORKAROUND - ESD_00_counter = 0; - ESD_00_Flag = 0; -#endif - if (!ts->use_irq) { - ret = cancel_work_sync(&ts->work); - if (ret) - himax_int_enable(ts->client->irq,1); - } - - //ts->first_pressed = 0; - atomic_set(&ts->suspend_mode, 1); - ts->pre_finger_mask = 0; - - if (ts->ts_pinctrl) { - ret = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_suspend); - if (ret < 0) { - E("Failed to get idle pinctrl state %d\n", ret); - } - } - - if (ts->pdata->powerOff3V3 && ts->pdata->power) - ts->pdata->power(0); - - return 0; -} - -int himax_chip_common_resume(struct himax_ts_data *ts) -{ - int retval; - - I("%s: enter \n", __func__); - - if (ts->pdata->powerOff3V3 && ts->pdata->power) - ts->pdata->power(1); - - - /*************************************/ - if (ts->protocol_type == PROTOCOL_TYPE_A) - input_mt_sync(ts->input_dev); - input_report_key(ts->input_dev, BTN_TOUCH, 0); - input_sync(ts->input_dev); - /*************************************/ - - - if (ts->ts_pinctrl) { - retval = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_active); - if (retval < 0) { - E("Cannot get default pinctrl state %d\n", retval); - goto err_pinctrl_select_resume; - } - } - - atomic_set(&ts->suspend_mode, 0); - - himax_int_enable(ts->client->irq,1); - - ts->suspended = false; -#if defined(HX_USB_DETECT2) - ts->usb_connected = 0x00; - himax_cable_detect_func(); -#endif -#ifdef HX_SMART_WAKEUP - queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(1000)); -#endif -#ifdef HX_HIGH_SENSE - queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(1000)); -#endif - return 0; -err_pinctrl_select_resume: - if (ts->pdata->powerOff3V3 && ts->pdata->power) - ts->pdata->power(0); - return retval; -} - diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h deleted file mode 100644 index 27ce9aafd959..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_common.h +++ /dev/null @@ -1,395 +0,0 @@ -/* Himax Android Driver Sample Code for Himax chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#ifndef HIMAX_COMMON_H -#define HIMAX_COMMON_H - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "himax_platform.h" - -#if defined(CONFIG_FB) -#include -#include -#elif defined(CONFIG_HAS_EARLYSUSPEND) -#include -#endif - -#ifdef CONFIG_OF -#include -#endif -#define HIMAX_DRIVER_VER "0.2.4.0" - -#define FLASH_DUMP_FILE "/data/user/Flash_Dump.bin" -#define DIAG_COORDINATE_FILE "/sdcard/Coordinate_Dump.csv" - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - -#define HX_TP_PROC_DIAG -#define HX_TP_PROC_REGISTER -#define HX_TP_PROC_DEBUG -#define HX_TP_PROC_FLASH_DUMP -#define HX_TP_PROC_SELF_TEST -#define HX_TP_PROC_RESET -#define HX_TP_PROC_SENSE_ON_OFF -//#define HX_TP_PROC_2T2R - -int himax_touch_proc_init(void); -void himax_touch_proc_deinit(void); -#endif - -//===========Himax Option function============= -//#define HX_RST_PIN_FUNC -//#define HX_AUTO_UPDATE_FW -//#define HX_HIGH_SENSE -//#define HX_SMART_WAKEUP -//#define HX_USB_DETECT -//#define HX_ESD_WORKAROUND -//#define HX_USB_DETECT2 - -//#define HX_EN_SEL_BUTTON // Support Self Virtual key ,default is close -#define HX_EN_MUT_BUTTON // Support Mutual Virtual Key ,default is close - -#define HX_KEY_MAX_COUNT 4 -#define DEFAULT_RETRY_CNT 3 - -#define HX_VKEY_0 KEY_BACK -#define HX_VKEY_1 KEY_HOME -#define HX_VKEY_2 KEY_RESERVED -#define HX_VKEY_3 KEY_RESERVED -#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3} - -#define SHIFTBITS 5 -//#define FLASH_SIZE 131072 -#define FW_SIZE_60k 61440 -#define FW_SIZE_64k 65536 -#define FW_SIZE_124k 126976 -#define FW_SIZE_128k 131072 - -struct himax_ic_data { - int vendor_fw_ver; - int vendor_config_ver; - int vendor_sensor_id; - int HX_RX_NUM; - int HX_TX_NUM; - int HX_BT_NUM; - int HX_X_RES; - int HX_Y_RES; - int HX_MAX_PT; - bool HX_XY_REVERSE; - bool HX_INT_IS_EDGE; -#ifdef HX_TP_PROC_2T2R - int HX_RX_NUM_2; - int HX_TX_NUM_2; -#endif -}; - -struct himax_virtual_key { - int index; - int keycode; - int x_range_min; - int x_range_max; - int y_range_min; - int y_range_max; -}; - -struct himax_config { - uint8_t default_cfg; - uint8_t sensor_id; - uint8_t fw_ver; - uint16_t length; - uint32_t tw_x_min; - uint32_t tw_x_max; - uint32_t tw_y_min; - uint32_t tw_y_max; - uint32_t pl_x_min; - uint32_t pl_x_max; - uint32_t pl_y_min; - uint32_t pl_y_max; - uint8_t c1[11]; - uint8_t c2[11]; - uint8_t c3[11]; - uint8_t c4[11]; - uint8_t c5[11]; - uint8_t c6[11]; - uint8_t c7[11]; - uint8_t c8[11]; - uint8_t c9[11]; - uint8_t c10[11]; - uint8_t c11[11]; - uint8_t c12[11]; - uint8_t c13[11]; - uint8_t c14[11]; - uint8_t c15[11]; - uint8_t c16[11]; - uint8_t c17[11]; - uint8_t c18[17]; - uint8_t c19[15]; - uint8_t c20[5]; - uint8_t c21[11]; - uint8_t c22[4]; - uint8_t c23[3]; - uint8_t c24[3]; - uint8_t c25[4]; - uint8_t c26[2]; - uint8_t c27[2]; - uint8_t c28[2]; - uint8_t c29[2]; - uint8_t c30[2]; - uint8_t c31[2]; - uint8_t c32[2]; - uint8_t c33[2]; - uint8_t c34[2]; - uint8_t c35[3]; - uint8_t c36[5]; - uint8_t c37[5]; - uint8_t c38[9]; - uint8_t c39[14]; - uint8_t c40[159]; - uint8_t c41[99]; -}; - -struct himax_ts_data { - bool suspended; - bool probe_done; - struct mutex fb_mutex; - atomic_t suspend_mode; - uint8_t x_channel; - uint8_t y_channel; - uint8_t useScreenRes; - uint8_t diag_command; - - uint8_t protocol_type; - uint8_t first_pressed; - uint8_t coord_data_size; - uint8_t area_data_size; - uint8_t raw_data_frame_size; - uint8_t raw_data_nframes; - uint8_t nFinger_support; - uint8_t irq_enabled; - uint8_t diag_self[50]; - - uint16_t finger_pressed; - uint16_t last_slot; - uint16_t pre_finger_mask; - - uint32_t debug_log_level; - uint32_t widthFactor; - uint32_t heightFactor; - uint32_t tw_x_min; - uint32_t tw_x_max; - uint32_t tw_y_min; - uint32_t tw_y_max; - uint32_t pl_x_min; - uint32_t pl_x_max; - uint32_t pl_y_min; - uint32_t pl_y_max; - - int use_irq; - int (*power)(int on); - int pre_finger_data[10][2]; - - struct device *dev; - struct workqueue_struct *himax_wq; - struct work_struct work; - struct input_dev *input_dev; - struct hrtimer timer; - struct i2c_client *client; - struct himax_i2c_platform_data *pdata; - struct himax_virtual_key *button; - -#if defined(CONFIG_FB) - struct notifier_block fb_notif; -#elif defined(CONFIG_HAS_EARLYSUSPEND) - struct early_suspend early_suspend; -#endif - -#ifdef HX_TP_PROC_FLASH_DUMP - struct workqueue_struct *flash_wq; - struct work_struct flash_work; -#endif - -#ifdef HX_RST_PIN_FUNC - int rst_gpio; -#endif - -#ifdef HX_TP_PROC_DIAG - struct workqueue_struct *himax_diag_wq; - struct delayed_work himax_diag_delay_wrok; -#endif -#ifdef HX_SMART_WAKEUP - uint8_t SMWP_enable; - uint8_t gesture_cust_en[16]; - struct wake_lock ts_SMWP_wake_lock; - struct workqueue_struct *himax_smwp_wq; - struct delayed_work smwp_work; -#endif - -#ifdef HX_HIGH_SENSE - uint8_t HSEN_enable; - struct workqueue_struct *himax_hsen_wq; - struct delayed_work hsen_work; -#endif - -#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) - uint8_t usb_connected; - uint8_t *cable_config; -#endif - - /* pinctrl data */ - struct pinctrl *ts_pinctrl; - struct pinctrl_state *pinctrl_state_active; - struct pinctrl_state *pinctrl_state_suspend; - struct pinctrl_state *pinctrl_state_release; -}; - -#define HX_CMD_NOP 0x00 -#define HX_CMD_SETMICROOFF 0x35 -#define HX_CMD_SETROMRDY 0x36 -#define HX_CMD_TSSLPIN 0x80 -#define HX_CMD_TSSLPOUT 0x81 -#define HX_CMD_TSSOFF 0x82 -#define HX_CMD_TSSON 0x83 -#define HX_CMD_ROE 0x85 -#define HX_CMD_RAE 0x86 -#define HX_CMD_RLE 0x87 -#define HX_CMD_CLRES 0x88 -#define HX_CMD_TSSWRESET 0x9E -#define HX_CMD_SETDEEPSTB 0xD7 -#define HX_CMD_SET_CACHE_FUN 0xDD -#define HX_CMD_SETIDLE 0xF2 -#define HX_CMD_SETIDLEDELAY 0xF3 -#define HX_CMD_SELFTEST_BUFFER 0x8D -#define HX_CMD_MANUALMODE 0x42 -#define HX_CMD_FLASH_ENABLE 0x43 -#define HX_CMD_FLASH_SET_ADDRESS 0x44 -#define HX_CMD_FLASH_WRITE_REGISTER 0x45 -#define HX_CMD_FLASH_SET_COMMAND 0x47 -#define HX_CMD_FLASH_WRITE_BUFFER 0x48 -#define HX_CMD_FLASH_PAGE_ERASE 0x4D -#define HX_CMD_FLASH_SECTOR_ERASE 0x4E -#define HX_CMD_CB 0xCB -#define HX_CMD_EA 0xEA -#define HX_CMD_4A 0x4A -#define HX_CMD_4F 0x4F -#define HX_CMD_B9 0xB9 -#define HX_CMD_76 0x76 - -enum input_protocol_type { - PROTOCOL_TYPE_A = 0x00, - PROTOCOL_TYPE_B = 0x01, -}; - -#ifdef HX_HIGH_SENSE -void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable); -#endif - -#ifdef HX_SMART_WAKEUP -#define GEST_PTLG_ID_LEN (4) -#define GEST_PTLG_HDR_LEN (4) -#define GEST_PTLG_HDR_ID1 (0xCC) -#define GEST_PTLG_HDR_ID2 (0x44) -#define GEST_PT_MAX_NUM (128) - -#ifdef HX_GESTURE_TRACK -static int gest_pt_cnt; -static int gest_pt_x[GEST_PT_MAX_NUM]; -static int gest_pt_y[GEST_PT_MAX_NUM]; -static int gest_start_x,gest_start_y,gest_end_x,gest_end_y; -static int gest_width,gest_height,gest_mid_x,gest_mid_y; -static int gn_gesture_coor[16]; -#endif - -void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable); -extern bool FAKE_POWER_KEY_SEND; - - enum gesture_event_type { - EV_GESTURE_01 = 0x01, - EV_GESTURE_02, - EV_GESTURE_03, - EV_GESTURE_04, - EV_GESTURE_05, - EV_GESTURE_06, - EV_GESTURE_07, - EV_GESTURE_08, - EV_GESTURE_09, - EV_GESTURE_10, - EV_GESTURE_11, - EV_GESTURE_12, - EV_GESTURE_13, - EV_GESTURE_14, - EV_GESTURE_15, - EV_GESTURE_PWR = 0x80, - }; - -#define KEY_CUST_01 251 -#define KEY_CUST_02 252 -#define KEY_CUST_03 253 -#define KEY_CUST_04 254 -#define KEY_CUST_05 255 -#define KEY_CUST_06 256 -#define KEY_CUST_07 257 -#define KEY_CUST_08 258 -#define KEY_CUST_09 259 -#define KEY_CUST_10 260 -#define KEY_CUST_11 261 -#define KEY_CUST_12 262 -#define KEY_CUST_13 263 -#define KEY_CUST_14 264 -#define KEY_CUST_15 265 -#endif - -#ifdef HX_ESD_WORKAROUND - extern u8 HX_ESD_RESET_ACTIVATE; -#endif - -extern int irq_enable_count; - -#ifdef QCT -irqreturn_t himax_ts_thread(int irq, void *ptr); -int himax_input_register(struct himax_ts_data *ts); -#endif - -extern int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id); -extern int himax_chip_common_remove(struct i2c_client *client); -extern int himax_chip_common_suspend(struct himax_ts_data *ts); -extern int himax_chip_common_resume(struct himax_ts_data *ts); -int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata); - -#ifdef HX_USB_DETECT2 -//extern kal_bool upmu_is_chr_det(void); -void himax_cable_detect_func(void); -#endif - -#endif - diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.c b/drivers/input/touchscreen/hxchipset/himax_debug.c deleted file mode 100644 index f8bee11b4351..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_debug.c +++ /dev/null @@ -1,2329 +0,0 @@ -/* Himax Android Driver Sample Code for Himax chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_debug.h" -#include "himax_ic.h" - -//struct himax_debug_data* debug_data; - -extern struct himax_ic_data* ic_data; -extern struct himax_ts_data *private_ts; -extern unsigned char IC_TYPE; -extern unsigned char IC_CHECKSUM; -extern int himax_input_register(struct himax_ts_data *ts); -#ifdef QCT -extern irqreturn_t himax_ts_thread(int irq, void *ptr); -#endif -#ifdef MTK -#ifdef CONFIG_OF_TOUCH -extern irqreturn_t tpd_eint_interrupt_handler(int irq, void *desc); -#else -extern void tpd_eint_interrupt_handler(void); -#endif -#endif - -#ifdef HX_TP_PROC_DIAG -#ifdef HX_TP_PROC_2T2R -int HX_RX_NUM_2 = 0; -int HX_TX_NUM_2 = 0; -#endif -int touch_monitor_stop_flag = 0; -int touch_monitor_stop_limit = 5; -uint8_t g_diag_arr_num = 0; -#endif - -#ifdef HX_ESD_WORKAROUND -u8 HX_ESD_RESET_ACTIVATE; -#endif - -#ifdef HX_SMART_WAKEUP -bool FAKE_POWER_KEY_SEND; -#endif - -//============================================================================================================= -// -// Segment : Himax PROC Debug Function -// -//============================================================================================================= -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - -static ssize_t himax_vendor_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - ssize_t ret = 0; - char *temp_buf; - - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - - ret += snprintf(temp_buf, len, "%s_FW:%#x_CFG:%#x_SensorId:%#x\n", HIMAX_common_NAME, - ic_data->vendor_fw_ver, ic_data->vendor_config_ver, ic_data->vendor_sensor_id); - HX_PROC_SEND_FLAG=1; - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; - - return ret; -} - -static const struct file_operations himax_proc_vendor_ops = -{ - .owner = THIS_MODULE, - .read = himax_vendor_read, -}; - -static ssize_t himax_attn_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - ssize_t ret = 0; - struct himax_ts_data *ts_data; - char *temp_buf; - - ts_data = private_ts; - - if (!HX_PROC_SEND_FLAG) { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "attn = %x\n", himax_int_gpio_read(ts_data->pdata->gpio_irq)); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - - return ret; -} - - -static const struct file_operations himax_proc_attn_ops = -{ - .owner = THIS_MODULE, - .read = himax_attn_read, -}; - -static ssize_t himax_int_en_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - size_t ret = 0; - char *temp_buf; - - if (!HX_PROC_SEND_FLAG) { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d ", ts->irq_enabled); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - return ret; -} - -static ssize_t himax_int_en_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - char buf_tmp[12]= {0}; - int value, ret=0; - - if (len >= 12) - { - I("%s: no command exceeds 12 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf_tmp, buff, len)) - { - return -EFAULT; - } - - if (buf_tmp[0] == '0') - value = false; - else if (buf_tmp[0] == '1') - value = true; - else - return -EINVAL; - - if (value) { - if(ic_data->HX_INT_IS_EDGE) - { -#ifdef MTK -#ifdef CONFIG_OF_TOUCH - himax_int_enable(ts->client->irq,1); -#else - //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); - //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); - mt_eint_registration(ts->client->irq, EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1); -#endif -#endif -#ifdef QCT - ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->client->name, ts); -#endif - } - else - { -#ifdef MTK -#ifdef CONFIG_OF_TOUCH - himax_int_enable(ts->client->irq,1); -#else - //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); - //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); - mt_eint_registration(ts->client->irq, EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1); -#endif -#endif -#ifdef QCT - ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts); -#endif - } - if (ret == 0) { - ts->irq_enabled = 1; - irq_enable_count = 1; - } - } else { - himax_int_enable(ts->client->irq,0); - free_irq(ts->client->irq, ts); - ts->irq_enabled = 0; - } - - return len; -} - -static const struct file_operations himax_proc_int_en_ops = -{ - .owner = THIS_MODULE, - .read = himax_int_en_read, - .write = himax_int_en_write, -}; - -static ssize_t himax_layout_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - size_t ret = 0; - char *temp_buf; - - if (!HX_PROC_SEND_FLAG) { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_x_max); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_min); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_max); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - - return ret; -} - -static ssize_t himax_layout_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - char buf_tmp[5]; - int i = 0, j = 0, k = 0, ret; - unsigned long value; - int layout[4] = {0}; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - for (i = 0; i < 20; i++) { - if (buf[i] == ',' || buf[i] == '\n') { - memset(buf_tmp, 0x0, sizeof(buf_tmp)); - if (i - j <= 5) - memcpy(buf_tmp, buf + j, i - j); - else { - I("buffer size is over 5 char\n"); - return len; - } - j = i + 1; - if (k < 4) { - ret = kstrtoul(buf_tmp, 10, &value); - layout[k++] = value; - } - } - } - if (k == 4) { - ts->pdata->abs_x_min=layout[0]; - ts->pdata->abs_x_max=layout[1]; - ts->pdata->abs_y_min=layout[2]; - ts->pdata->abs_y_max=layout[3]; - I("%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); - input_unregister_device(ts->input_dev); - himax_input_register(ts); - } else - I("ERR@%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); - return len; -} - -static const struct file_operations himax_proc_layout_ops = -{ - .owner = THIS_MODULE, - .read = himax_layout_read, - .write = himax_layout_write, -}; - -static ssize_t himax_debug_level_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts_data; - size_t ret = 0; - char *temp_buf; - ts_data = private_ts; - - if (!HX_PROC_SEND_FLAG) { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d\n", ts_data->debug_log_level); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - - return ret; -} - -static ssize_t himax_debug_level_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts; - char buf_tmp[11]; - int i; - ts = private_ts; - - if (len >= 12) - { - I("%s: no command exceeds 12 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf_tmp, buff, len)) - { - return -EFAULT; - } - - ts->debug_log_level = 0; - for(i=0; i='0' && buf_tmp[i]<='9' ) - ts->debug_log_level |= (buf_tmp[i]-'0'); - else if( buf_tmp[i]>='A' && buf_tmp[i]<='F' ) - ts->debug_log_level |= (buf_tmp[i]-'A'+10); - else if( buf_tmp[i]>='a' && buf_tmp[i]<='f' ) - ts->debug_log_level |= (buf_tmp[i]-'a'+10); - - if(i!=len-2) - ts->debug_log_level <<= 4; - } - - if (ts->debug_log_level & BIT(3)) { - if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 && - (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 && - (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { - ts->widthFactor = (ts->pdata->screenWidth << SHIFTBITS)/(ts->pdata->abs_x_max - ts->pdata->abs_x_min); - ts->heightFactor = (ts->pdata->screenHeight << SHIFTBITS)/(ts->pdata->abs_y_max - ts->pdata->abs_y_min); - if (ts->widthFactor > 0 && ts->heightFactor > 0) - ts->useScreenRes = 1; - else { - ts->heightFactor = 0; - ts->widthFactor = 0; - ts->useScreenRes = 0; - } - } else - I("Enable finger debug with raw position mode!\n"); - } else { - ts->useScreenRes = 0; - ts->widthFactor = 0; - ts->heightFactor = 0; - } - - return len; -} - -static const struct file_operations himax_proc_debug_level_ops = -{ - .owner = THIS_MODULE, - .read = himax_debug_level_read, - .write = himax_debug_level_write, -}; - -#ifdef HX_TP_PROC_REGISTER -static ssize_t himax_proc_register_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - int ret = 0; - uint16_t loop_i; - uint8_t data[128]; - char *temp_buf; - - memset(data, 0x00, sizeof(data)); - - I("himax_register_show: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - himax_register_read(private_ts->client, register_command, 1, data); - - ret += snprintf(temp_buf, len, "command: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); - - for (loop_i = 0; loop_i < 128; loop_i++) { - ret += snprintf(temp_buf+ret, len-ret, "0x%2.2X ", data[loop_i]); - if ((loop_i % 16) == 15) - ret += snprintf(temp_buf+ret, len-ret, "\n"); - } - ret += snprintf(temp_buf+ret, len-ret, "\n"); - HX_PROC_SEND_FLAG=1; - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; - return ret; -} - -static ssize_t himax_proc_register_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - char buf_tmp[16], length = 0; - unsigned long result = 0; - uint8_t loop_i = 0; - uint16_t base = 5; - uint8_t write_da[128]; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - memset(buf_tmp, 0x0, sizeof(buf_tmp)); - memset(write_da, 0x0, sizeof(write_da)); - - I("himax %s \n",buf); - - if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') { - - if (buf[2] == 'x') { - memcpy(buf_tmp, buf + 3, 8); - if (!kstrtoul(buf_tmp, 16, &result)) - { - register_command[0] = (uint8_t)result; - register_command[1] = (uint8_t)(result >> 8); - register_command[2] = (uint8_t)(result >> 16); - register_command[3] = (uint8_t)(result >> 24); - } - base = 11; - I("CMD: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); - - for (loop_i = 0; loop_i < 128 && (base+10)<80; loop_i++) { - if (buf[base] == '\n') { - if (buf[0] == 'w') { - himax_register_write(private_ts->client, register_command, 1, write_da); - I("CMD: %x, %x, %x, %x, len=%d\n", write_da[0], write_da[1],write_da[2],write_da[3],length); - } - I("\n"); - return len; - } - if (buf[base + 1] == 'x') { - buf_tmp[10] = '\n'; - buf_tmp[11] = '\0'; - memcpy(buf_tmp, buf + base + 2, 8); - if (!kstrtoul(buf_tmp, 16, &result)) { - write_da[loop_i] = (uint8_t)result; - write_da[loop_i+1] = (uint8_t)(result >> 8); - write_da[loop_i+2] = (uint8_t)(result >> 16); - write_da[loop_i+3] = (uint8_t)(result >> 24); - } - length+=4; - } - base += 10; - } - } - } - return len; -} - -static const struct file_operations himax_proc_register_ops = -{ - .owner = THIS_MODULE, - .read = himax_proc_register_read, - .write = himax_proc_register_write, -}; -#endif - -#ifdef HX_TP_PROC_DIAG -int16_t *getMutualBuffer(void) -{ - return diag_mutual; -} -int16_t *getMutualNewBuffer(void) -{ - return diag_mutual_new; -} -int16_t *getMutualOldBuffer(void) -{ - return diag_mutual_old; -} -int16_t *getSelfBuffer(void) -{ - return &diag_self[0]; -} -uint8_t getXChannel(void) -{ - return x_channel; -} -uint8_t getYChannel(void) -{ - return y_channel; -} -uint8_t getDiagCommand(void) -{ - return diag_command; -} -void setXChannel(uint8_t x) -{ - x_channel = x; -} -void setYChannel(uint8_t y) -{ - y_channel = y; -} -void setMutualBuffer(void) -{ - diag_mutual = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); -} -void setMutualNewBuffer(void) -{ - diag_mutual_new = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); -} -void setMutualOldBuffer(void) -{ - diag_mutual_old = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); -} - -#ifdef HX_TP_PROC_2T2R -int16_t *getMutualBuffer_2(void) -{ - return diag_mutual_2; -} -uint8_t getXChannel_2(void) -{ - return x_channel_2; -} -uint8_t getYChannel_2(void) -{ - return y_channel_2; -} -void setXChannel_2(uint8_t x) -{ - x_channel_2 = x; -} -void setYChannel_2(uint8_t y) -{ - y_channel_2 = y; -} -void setMutualBuffer_2(void) -{ - diag_mutual_2 = kzalloc(x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL); -} -#endif - -static ssize_t himax_diag_arrange_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - //struct himax_ts_data *ts = private_ts; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - g_diag_arr_num = buf[0] - '0'; - I("%s: g_diag_arr_num = %d \n", __func__,g_diag_arr_num); - - return len; -} - -static const struct file_operations himax_proc_diag_arrange_ops = -{ - .owner = THIS_MODULE, - .write = himax_diag_arrange_write, -}; - -static void himax_diag_arrange_print(struct seq_file *s, int i, int j, int transpose) -{ - if(transpose) - seq_printf(s, "%6d", diag_mutual[ j + i*x_channel]); - else - seq_printf(s, "%6d", diag_mutual[ i + j*x_channel]); -} - -static void himax_diag_arrange_inloop(struct seq_file *s, int in_init,bool transpose, int j) -{ - int i; - int in_max = 0; - - if(transpose) - in_max = y_channel; - else - in_max = x_channel; - - if (in_init > 0) - { - for(i = in_init-1;i >= 0;i--) - { - himax_diag_arrange_print(s, i, j, transpose); - } - } - else - { - for (i = 0; i < in_max; i++) - { - himax_diag_arrange_print(s, i, j, transpose); - } - } -} - -static void himax_diag_arrange_outloop(struct seq_file *s, int transpose, int out_init, int in_init) -{ - int j; - int out_max = 0; - - if(transpose) - out_max = x_channel; - else - out_max = y_channel; - - if(out_init > 0) - { - for(j = out_init-1;j >= 0;j--) - { - himax_diag_arrange_inloop(s, in_init, transpose, j); - seq_printf(s, " %5d\n", diag_self[j]); - } - } - else - { - for(j = 0;j < out_max;j++) - { - himax_diag_arrange_inloop(s, in_init, transpose, j); - seq_printf(s, " %5d\n", diag_self[j]); - } - } -} - -static void himax_diag_arrange(struct seq_file *s) -{ - int bit2,bit1,bit0; - int i; - - bit2 = g_diag_arr_num >> 2; - bit1 = g_diag_arr_num >> 1 & 0x1; - bit0 = g_diag_arr_num & 0x1; - - if (g_diag_arr_num < 4) - { - himax_diag_arrange_outloop(s, bit2, bit1 * y_channel, bit0 * x_channel); - for (i = y_channel; i < x_channel + y_channel; i++) { - seq_printf(s, "%6d", diag_self[i]); - } - } - else - { - himax_diag_arrange_outloop(s, bit2, bit1 * x_channel, bit0 * y_channel); - for (i = x_channel; i < x_channel + y_channel; i++) { - seq_printf(s, "%6d", diag_self[i]); - } - } -} - -static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos) -{ - if (*pos>=1) return NULL; - return (void *)((unsigned long) *pos+1); -} - -static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) -{ - return NULL; -} -static void himax_diag_seq_stop(struct seq_file *s, void *v) -{ -} -static int himax_diag_seq_read(struct seq_file *s, void *v) -{ - size_t count = 0; - int32_t loop_i;//,loop_j - uint16_t mutual_num, self_num, width; - -#ifdef HX_TP_PROC_2T2R - if(Is_2T2R && diag_command == 4) - { - mutual_num = x_channel_2 * y_channel_2; - self_num = x_channel_2 + y_channel_2; //don't add KEY_COUNT - width = x_channel_2; - seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel_2, y_channel_2); - } - else -#endif - { - mutual_num = x_channel * y_channel; - self_num = x_channel + y_channel; //don't add KEY_COUNT - width = x_channel; - seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel, y_channel); - } - - // start to show out the raw data in adb shell - if (diag_command >= 1 && diag_command <= 6) { - if (diag_command <= 3) { - himax_diag_arrange(s); - seq_printf(s, "\n\n"); -#ifdef HX_EN_SEL_BUTTON - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) - seq_printf(s, "%6d", diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]); -#endif -#ifdef HX_TP_PROC_2T2R - }else if(Is_2T2R && diag_command == 4 ) { - for (loop_i = 0; loop_i < mutual_num; loop_i++) { - seq_printf(s, "%4d", diag_mutual_2[loop_i]); - if ((loop_i % width) == (width - 1)) - seq_printf(s, " %6d\n", diag_self[width + loop_i/width]); - } - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < width; loop_i++) { - seq_printf(s, "%6d", diag_self[loop_i]); - if (((loop_i) % width) == (width - 1)) - seq_printf(s, "\n"); - } -#ifdef HX_EN_SEL_BUTTON - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) - seq_printf(s, "%4d", diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]); -#endif -#endif - } else if (diag_command > 4) { - for (loop_i = 0; loop_i < self_num; loop_i++) { - seq_printf(s, "%4d", diag_self[loop_i]); - if (((loop_i - mutual_num) % width) == (width - 1)) - seq_printf(s, "\n"); - } - } else { - for (loop_i = 0; loop_i < mutual_num; loop_i++) { - seq_printf(s, "%4d", diag_mutual[loop_i]); - if ((loop_i % width) == (width - 1)) - seq_printf(s, "\n"); - } - } - seq_printf(s, "ChannelEnd"); - seq_printf(s, "\n"); - } else if (diag_command == 7) { - for (loop_i = 0; loop_i < 128 ;loop_i++) { - if ((loop_i % 16) == 0) - seq_printf(s, "LineStart:"); - seq_printf(s, "%4d", diag_coor[loop_i]); - if ((loop_i % 16) == 15) - seq_printf(s, "\n"); - } - } else if (diag_command == 9 || diag_command == 91 || diag_command == 92){ - himax_diag_arrange(s); - seq_printf(s, "\n"); - } - - return count; -} -static const struct seq_operations himax_diag_seq_ops = -{ - .start = himax_diag_seq_start, - .next = himax_diag_seq_next, - .stop = himax_diag_seq_stop, - .show = himax_diag_seq_read, -}; -static int himax_diag_proc_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &himax_diag_seq_ops); -}; -bool DSRAM_Flag; - -//DSRAM thread -void himax_ts_diag_func(void) -{ - int i=0, j=0; - unsigned int index = 0; - int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; - uint8_t info_data[total_size]; - int16_t *mutual_data = NULL; - int16_t *mutual_data_new = NULL; - int16_t *mutual_data_old = NULL; - int16_t new_data; - - himax_burst_enable(private_ts->client, 1); - if(diag_command == 9 || diag_command == 91) - { - mutual_data = getMutualBuffer(); - }else if(diag_command == 92){ - mutual_data = getMutualBuffer(); - mutual_data_new = getMutualNewBuffer(); - mutual_data_old = getMutualOldBuffer(); - } - himax_get_DSRAM_data(private_ts->client, info_data); - - index = 0; - for (i = 0; i < ic_data->HX_TX_NUM; i++) - { - for (j = 0; j < ic_data->HX_RX_NUM; j++) - { - new_data = (short)(info_data[index + 1] << 8 | info_data[index]); - if(diag_command == 9){ - mutual_data[i*ic_data->HX_RX_NUM+j] = new_data; - }else if(diag_command == 91){ //Keep max data for 100 frame - if(mutual_data[i * ic_data->HX_RX_NUM + j] < new_data) - mutual_data[i * ic_data->HX_RX_NUM + j] = new_data; - }else if(diag_command == 92){ //Cal data for [N]-[N-1] frame - mutual_data_new[i * ic_data->HX_RX_NUM + j] = new_data; - mutual_data[i * ic_data->HX_RX_NUM + j] = mutual_data_new[i * ic_data->HX_RX_NUM + j] - mutual_data_old[i * ic_data->HX_RX_NUM + j]; - } - index += 2; - } - } - if(diag_command == 92){ - memcpy(mutual_data_old,mutual_data_new,x_channel * y_channel * sizeof(int16_t)); //copy N data to N-1 array - } - diag_max_cnt++; - if(diag_command == 9 || diag_command == 92){ - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); - }else if(diag_command == 91){ - if(diag_max_cnt > 100) //count for 100 frame - { - //Clear DSRAM flag - DSRAM_Flag = false; - - //Enable ISR - himax_int_enable(private_ts->client->irq,1); - - //===================================== - // test result command : 0x8002_0324 ==> 0x00 - //===================================== - himax_diag_register_set(private_ts->client, 0x00); - }else{ - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); - } - } -} - -static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size_t len, loff_t *data) -{ - char messages[80] = {0}; - - uint8_t command[2] = {0x00, 0x00}; - uint8_t receive[1]; - - memset(receive, 0x00, sizeof(receive)); - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(messages, buff, len)) - { - return -EFAULT; - } - if (messages[1] == 0x0A){ - diag_command =messages[0] - '0'; - }else{ - diag_command =(messages[0] - '0')*10 + (messages[1] - '0'); - } - - I("[Himax]diag_command=0x%x\n",diag_command); - if (diag_command < 0x04){ - if(DSRAM_Flag) - { - //1. Clear DSRAM flag - DSRAM_Flag = false; - - //2. Stop DSRAM thread - cancel_delayed_work_sync(&private_ts->himax_diag_delay_wrok); - - //3. Enable ISR - himax_int_enable(private_ts->client->irq,1); - } - command[0] = diag_command; - himax_diag_register_set(private_ts->client, command[0]); - } - //coordinate dump start - else if (diag_command == 0x08) { - E("%s: coordinate_dump_file_create error\n", __func__); - } - else if (diag_command == 0x09 || diag_command == 91 || diag_command == 92){ - diag_max_cnt = 0; - memset(diag_mutual, 0x00, x_channel * y_channel * sizeof(int16_t)); //Set data 0 everytime - - //1. Disable ISR - himax_int_enable(private_ts->client->irq,0); - - //2. Start DSRAM thread - //himax_diag_register_set(private_ts->client, 0x0A); - - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 2*HZ/100); - - I("%s: Start get raw data in DSRAM\n", __func__); - - //3. Set DSRAM flag - DSRAM_Flag = true; - }else{ - command[0] = 0x00; - himax_diag_register_set(private_ts->client, command[0]); - E("[Himax]Diag command error!diag_command=0x%x\n",diag_command); - } - return len; -} - -static const struct file_operations himax_proc_diag_ops = -{ - .owner = THIS_MODULE, - .open = himax_diag_proc_open, - .read = seq_read, - .write = himax_diag_write, -}; -#endif - -#ifdef HX_TP_PROC_RESET -static ssize_t himax_reset_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - char buf_tmp[12]; - - if (len >= 12) - { - I("%s: no command exceeds 12 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf_tmp, buff, len)) - { - return -EFAULT; - } - //if (buf_tmp[0] == '1') - // ESD_HW_REST(); - - return len; -} - -static const struct file_operations himax_proc_reset_ops = -{ - .owner = THIS_MODULE, - .write = himax_reset_write, -}; -#endif - -#ifdef HX_TP_PROC_DEBUG -static ssize_t himax_debug_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - size_t count = 0; - char *temp_buf; - - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf){ - HX_PROC_SEND_FLAG=0; - return count; - } - - if (debug_level_cmd == 't') - { - if (fw_update_complete) - count += snprintf(temp_buf+count, len-count, "FW Update Complete "); - else - { - count += snprintf(temp_buf+count, len-count, "FW Update Fail "); - } - } - else if (debug_level_cmd == 'h') - { - if (handshaking_result == 0) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Running)\n", handshaking_result); - } - else if (handshaking_result == 1) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Stop)\n", handshaking_result); - } - else if (handshaking_result == 2) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (I2C Error)\n", handshaking_result); - } - else - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = error\n"); - } - } - else if (debug_level_cmd == 'v') - { - count += snprintf(temp_buf+count, len-count, "FW_VER = "); - count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_fw_ver); - count += snprintf(temp_buf+count, len-count, "CONFIG_VER = "); - count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_config_ver); - count += snprintf(temp_buf+count, len-count, "\n"); - } - else if (debug_level_cmd == 'd') - { - count += snprintf(temp_buf+count, len-count, "Himax Touch IC Information :\n"); - if (IC_TYPE == HX_85XX_D_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : D\n"); - } - else if (IC_TYPE == HX_85XX_E_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : E\n"); - } - else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : ES\n"); - } - else if (IC_TYPE == HX_85XX_F_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : F\n"); - } - else - { - count += snprintf(temp_buf+count, len-count, "IC Type error.\n"); - } - - if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : SW\n"); - } - else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : HW\n"); - } - else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : CRC\n"); - } - else - { - count += snprintf(temp_buf+count, len-count, "IC Checksum error.\n"); - } - - if (ic_data->HX_INT_IS_EDGE) - { - count += snprintf(temp_buf+count, len-count, "Interrupt : EDGE TIRGGER\n"); - } - else - { - count += snprintf(temp_buf+count, len-count, "Interrupt : LEVEL TRIGGER\n"); - } - - count += snprintf(temp_buf+count, len-count, "RX Num : %d\n", ic_data->HX_RX_NUM); - count += snprintf(temp_buf+count, len-count, "TX Num : %d\n", ic_data->HX_TX_NUM); - count += snprintf(temp_buf+count, len-count, "BT Num : %d\n", ic_data->HX_BT_NUM); - count += snprintf(temp_buf+count, len-count, "X Resolution : %d\n", ic_data->HX_X_RES); - count += snprintf(temp_buf+count, len-count, "Y Resolution : %d\n", ic_data->HX_Y_RES); - count += snprintf(temp_buf+count, len-count, "Max Point : %d\n", ic_data->HX_MAX_PT); - count += snprintf(temp_buf+count, len-count, "XY reverse : %d\n", ic_data->HX_XY_REVERSE); - #ifdef HX_TP_PROC_2T2R - if(Is_2T2R) - { - count += snprintf(temp_buf+count, len-count, "2T2R panel\n"); - count += snprintf(temp_buf+count, len-count, "RX Num_2 : %d\n", HX_RX_NUM_2); - count += snprintf(temp_buf+count, len-count, "TX Num_2 : %d\n", HX_TX_NUM_2); - } - #endif - } - else if (debug_level_cmd == 'i') - { - count += snprintf(temp_buf+count, len-count, "Himax Touch Driver Version:\n"); - count += snprintf(temp_buf+count, len-count, "%s\n", HIMAX_DRIVER_VER); - } - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG=1; - } - else - HX_PROC_SEND_FLAG=0; - return count; -} - -static ssize_t himax_debug_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - const struct firmware *fw = NULL; - unsigned char *fw_data = NULL; - char fileName[128]; - char buf[80] = {0}; - int result; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - if ( buf[0] == 'h') //handshaking - { - debug_level_cmd = buf[0]; - - himax_int_enable(private_ts->client->irq,0); - - handshaking_result = himax_hand_shaking(private_ts->client); //0:Running, 1:Stop, 2:I2C Fail - - himax_int_enable(private_ts->client->irq,1); - - return len; - } - - else if ( buf[0] == 'v') //firmware version - { - debug_level_cmd = buf[0]; - himax_int_enable(private_ts->client->irq,0); -#ifdef HX_RST_PIN_FUNC - himax_HW_reset(false,false); -#endif - himax_read_FW_ver(private_ts->client); - //himax_check_chip_version(); -#ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); -#endif - himax_int_enable(private_ts->client->irq,1); - return len; - } - - else if ( buf[0] == 'd') //ic information - { - debug_level_cmd = buf[0]; - return len; - } - - else if ( buf[0] == 'i') //driver version - { - debug_level_cmd = buf[0]; - return len; - } - - else if (buf[0] == 't') - { - - himax_int_enable(private_ts->client->irq,0); - - debug_level_cmd = buf[0]; - fw_update_complete = false; - - memset(fileName, 0, 128); - // parse the file name - snprintf(fileName, len-4, "%s", &buf[4]); - I("%s: upgrade from file(%s) start!\n", __func__, fileName); - // open file - result = request_firmware(&fw, fileName, private_ts->dev); - if (result) { - E("%s: open firmware file failed\n", __func__); - goto firmware_upgrade_done; - //return len; - } - - I("%s: FW len %d\n", __func__, fw->size); - fw_data = (unsigned char *)fw->data; - - I("%s: FW image,len %d: %02X, %02X, %02X, %02X\n", __func__, result, upgrade_fw[0], upgrade_fw[1], upgrade_fw[2], upgrade_fw[3]); - - if (fw_data != NULL) - { - // start to upgrade - himax_int_enable(private_ts->client->irq,0); - - if ((buf[1] == '6') && (buf[2] == '0')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); - fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); - fw_update_complete = true; - } - } - else if ((buf[1] == '6') && (buf[2] == '4')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); - fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); - fw_update_complete = true; - } - } - else if ((buf[1] == '2') && (buf[2] == '4')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); - fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); - fw_update_complete = true; - } - } - else if ((buf[1] == '2') && (buf[2] == '8')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); - fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); - fw_update_complete = true; - } - } - else - { - E("%s: Flash command fail: %d\n", __func__, __LINE__); - fw_update_complete = false; - } - release_firmware(fw); - goto firmware_upgrade_done; - //return count; - } - } - - firmware_upgrade_done: - -#ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); -#endif - - himax_sense_on(private_ts->client, 0x01); - msleep(120); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - himax_int_enable(private_ts->client->irq,1); - - //todo himax_chip->tp_firmware_upgrade_proceed = 0; - //todo himax_chip->suspend_state = 0; - //todo enable_irq(himax_chip->irq); - return len; -} - -static const struct file_operations himax_proc_debug_ops = -{ - .owner = THIS_MODULE, - .read = himax_debug_read, - .write = himax_debug_write, -}; - -#endif - -#ifdef HX_TP_PROC_FLASH_DUMP - -static uint8_t getFlashCommand(void) -{ - return flash_command; -} - -static uint8_t getFlashDumpProgress(void) -{ - return flash_progress; -} - -static uint8_t getFlashDumpComplete(void) -{ - return flash_dump_complete; -} - -static uint8_t getFlashDumpFail(void) -{ - return flash_dump_fail; -} - -uint8_t getSysOperation(void) -{ - return sys_operation; -} - -static uint8_t getFlashReadStep(void) -{ - return flash_read_step; -} -/* -static uint8_t getFlashDumpSector(void) -{ - return flash_dump_sector; -} - -static uint8_t getFlashDumpPage(void) -{ - return flash_dump_page; -} -*/ -bool getFlashDumpGoing(void) -{ - return flash_dump_going; -} - -void setFlashBuffer(void) -{ - flash_buffer = kzalloc(Flash_Size * sizeof(uint8_t), GFP_KERNEL); - if (flash_buffer) - memset(flash_buffer,0x00,Flash_Size); -} - -void setSysOperation(uint8_t operation) -{ - sys_operation = operation; -} - -static void setFlashDumpProgress(uint8_t progress) -{ - flash_progress = progress; - //I("setFlashDumpProgress : progress = %d ,flash_progress = %d \n",progress,flash_progress); -} - -static void setFlashDumpComplete(uint8_t status) -{ - flash_dump_complete = status; -} - -static void setFlashDumpFail(uint8_t fail) -{ - flash_dump_fail = fail; -} - -static void setFlashCommand(uint8_t command) -{ - flash_command = command; -} - -static void setFlashReadStep(uint8_t step) -{ - flash_read_step = step; -} - -static void setFlashDumpSector(uint8_t sector) -{ - flash_dump_sector = sector; -} - -static void setFlashDumpPage(uint8_t page) -{ - flash_dump_page = page; -} - -static void setFlashDumpGoing(bool going) -{ - flash_dump_going = going; -} - -static ssize_t himax_proc_flash_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - int ret = 0; - int loop_i; - uint8_t local_flash_read_step=0; - uint8_t local_flash_complete = 0; - uint8_t local_flash_progress = 0; - uint8_t local_flash_command = 0; - uint8_t local_flash_fail = 0; - char *temp_buf; - local_flash_complete = getFlashDumpComplete(); - local_flash_progress = getFlashDumpProgress(); - local_flash_command = getFlashCommand(); - local_flash_fail = getFlashDumpFail(); - - I("flash_progress = %d \n",local_flash_progress); - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - - if (local_flash_fail) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Fail \n"); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - return ret; - } - - if (!local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Ongoing:0x%2.2x \n",flash_progress); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - return ret; - } - - if (local_flash_command == 1 && local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Complete \n"); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - return ret; - } - - if (local_flash_command == 3 && local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart: \n"); - for(loop_i = 0; loop_i < 128; loop_i++) - { - ret += snprintf(temp_buf+ret, len-ret, "x%2.2x", flash_buffer[loop_i]); - if ((loop_i % 16) == 15) - { - ret += snprintf(temp_buf+ret, len-ret, "\n"); - } - } - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - return ret; - } - - //flash command == 0 , report the data - local_flash_read_step = getFlashReadStep(); - - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:%2.2x \n",local_flash_read_step); - - for (loop_i = 0; loop_i < 1024; loop_i++) - { - ret += snprintf(temp_buf+ret, len-ret, "x%2.2X", flash_buffer[local_flash_read_step*1024 + loop_i]); - - if ((loop_i % 16) == 15) - { - ret += snprintf(temp_buf+ret, len-ret, "\n"); - } - } - - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - return ret; -} - -static ssize_t himax_proc_flash_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - char buf_tmp[6]; - unsigned long result = 0; - uint8_t loop_i = 0; - int base = 0; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - memset(buf_tmp, 0x0, sizeof(buf_tmp)); - - I("%s: buf[0] = %s\n", __func__, buf); - - if (getSysOperation() == 1) - { - E("%s: PROC is busy , return!\n", __func__); - return len; - } - - if (buf[0] == '0') - { - setFlashCommand(0); - if (buf[1] == ':' && buf[2] == 'x') - { - memcpy(buf_tmp, buf + 3, 2); - I("%s: read_Step = %s\n", __func__, buf_tmp); - if (!kstrtoul(buf_tmp, 16, &result)) - { - I("%s: read_Step = %lu \n", __func__, result); - setFlashReadStep(result); - } - } - } - else if (buf[0] == '1')// 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k - { - setSysOperation(1); - setFlashCommand(1); - setFlashDumpProgress(0); - setFlashDumpComplete(0); - setFlashDumpFail(0); - if ((buf[1] == '_' ) && (buf[2] == '6' )){ - if (buf[3] == '0'){ - Flash_Size = FW_SIZE_60k; - }else if (buf[3] == '4'){ - Flash_Size = FW_SIZE_64k; - } - }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ - if (buf[3] == '4'){ - Flash_Size = FW_SIZE_124k; - }else if (buf[3] == '8'){ - Flash_Size = FW_SIZE_128k; - } - } - queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '2') // 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k - { - setSysOperation(1); - setFlashCommand(2); - setFlashDumpProgress(0); - setFlashDumpComplete(0); - setFlashDumpFail(0); - if ((buf[1] == '_' ) && (buf[2] == '6' )){ - if (buf[3] == '0'){ - Flash_Size = FW_SIZE_60k; - }else if (buf[3] == '4'){ - Flash_Size = FW_SIZE_64k; - } - }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ - if (buf[3] == '4'){ - Flash_Size = FW_SIZE_124k; - }else if (buf[3] == '8'){ - Flash_Size = FW_SIZE_128k; - } - } - queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '3') - { - setSysOperation(1); - setFlashCommand(3); - setFlashDumpProgress(0); - setFlashDumpComplete(0); - setFlashDumpFail(0); - - memcpy(buf_tmp, buf + 3, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { - setFlashDumpSector(result); - } - - memcpy(buf_tmp, buf + 7, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { - setFlashDumpPage(result); - } - - queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '4') - { - I("%s: command 4 enter.\n", __func__); - setSysOperation(1); - setFlashCommand(4); - setFlashDumpProgress(0); - setFlashDumpComplete(0); - setFlashDumpFail(0); - - memcpy(buf_tmp, buf + 3, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { - setFlashDumpSector(result); - } - else - { - E("%s: command 4 , sector error.\n", __func__); - return len; - } - - memcpy(buf_tmp, buf + 7, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { - setFlashDumpPage(result); - } - else - { - E("%s: command 4 , page error.\n", __func__); - return len; - } - - base = 11; - - I("=========Himax flash page buffer start=========\n"); - for(loop_i=0;loop_i<128 && base<80;loop_i++) - { - memcpy(buf_tmp, buf + base, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { - flash_buffer[loop_i] = result; - I("%d ",flash_buffer[loop_i]); - if (loop_i % 16 == 15) - { - I("\n"); - } - } - base += 3; - } - I("=========Himax flash page buffer end=========\n"); - - queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - return len; -} - -static const struct file_operations himax_proc_flash_ops = -{ - .owner = THIS_MODULE, - .read = himax_proc_flash_read, - .write = himax_proc_flash_write, -}; - -void himax_ts_flash_func(void) -{ - uint8_t local_flash_command = 0; - - himax_int_enable(private_ts->client->irq,0); - setFlashDumpGoing(true); - - //sector = getFlashDumpSector(); - //page = getFlashDumpPage(); - - local_flash_command = getFlashCommand(); - - msleep(100); - - I("%s: local_flash_command = %d enter.\n", __func__,local_flash_command); - - if ((local_flash_command == 1 || local_flash_command == 2)|| (local_flash_command==0x0F)) - { - himax_flash_dump_func(private_ts->client, local_flash_command,Flash_Size, flash_buffer); - } - - I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); - - if (local_flash_command == 2) - { - E("Flash dump failed\n"); - } - - himax_int_enable(private_ts->client->irq,1); - setFlashDumpGoing(false); - - setFlashDumpComplete(1); - setSysOperation(0); - return; - -/* Flash_Dump_i2c_transfer_error: - - himax_int_enable(private_ts->client->irq,1); - setFlashDumpGoing(false); - setFlashDumpComplete(0); - setFlashDumpFail(1); - setSysOperation(0); - return; -*/ -} - -#endif - -#ifdef HX_TP_PROC_SELF_TEST -static ssize_t himax_self_test_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - int val=0x00; - int ret = 0; - char *temp_buf; - - I("%s: enter, %d \n", __func__, __LINE__); - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - himax_int_enable(private_ts->client->irq,0);//disable irq - val = himax_chip_self_test(private_ts->client); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - himax_int_enable(private_ts->client->irq,1);//enable irq - - if (val == 0x01) { - ret += snprintf(temp_buf+ret, len-ret, "Self_Test Pass\n"); - } else { - ret += snprintf(temp_buf+ret, len-ret, "Self_Test Fail\n"); - } - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - return ret; -} - -/* -static ssize_t himax_chip_self_test_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count) -{ - char buf_tmp[2]; - unsigned long result = 0; - - memset(buf_tmp, 0x0, sizeof(buf_tmp)); - memcpy(buf_tmp, buf, 2); - if(!kstrtoul(buf_tmp, 16, &result)) - { - sel_type = (uint8_t)result; - } - I("sel_type = %x \r\n", sel_type); - return count; -} -*/ - -static const struct file_operations himax_proc_self_test_ops = -{ - .owner = THIS_MODULE, - .read = himax_self_test_read, -}; -#endif - -#ifdef HX_TP_PROC_SENSE_ON_OFF -static ssize_t himax_sense_on_off_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - if(buf[0] == '0') - { - himax_sense_off(private_ts->client); - I("Sense off \n"); - } - else if(buf[0] == '1') - { - if(buf[1] == '1'){ - himax_sense_on(private_ts->client, 0x01); - I("Sense on re-map off, run flash \n"); - }else if(buf[1] == '0'){ - himax_sense_on(private_ts->client, 0x00); - I("Sense on re-map on, run sram \n"); - }else{ - I("Do nothing \n"); - } - } - else - { - I("Do nothing \n"); - } - return len; -} - -static const struct file_operations himax_proc_sense_on_off_ops = -{ - .owner = THIS_MODULE, - .write = himax_sense_on_off_write, -}; -#endif - -#ifdef HX_HIGH_SENSE -static ssize_t himax_HSEN_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - size_t count = 0; - char *temp_buf; - - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return count; - } - count = snprintf(temp_buf, len, "%d\n", ts->HSEN_enable); - HX_PROC_SEND_FLAG=1; - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; - return count; -} - -static ssize_t himax_HSEN_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - char buf[80] = {0}; - - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - if (buf[0] == '0'){ - ts->HSEN_enable = 0; - } - else if (buf[0] == '1'){ - ts->HSEN_enable = 1; - } - else - return -EINVAL; - - himax_set_HSEN_func(ts->client, ts->HSEN_enable); - - I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable); - - return len; -} - -static const struct file_operations himax_proc_HSEN_ops = -{ - .owner = THIS_MODULE, - .read = himax_HSEN_read, - .write = himax_HSEN_write, -}; -#endif - -#ifdef HX_SMART_WAKEUP -static ssize_t himax_SMWP_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - size_t count = 0; - struct himax_ts_data *ts = private_ts; - char *temp_buf; - - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return count; - } - count = snprintf(temp_buf, len, "%d\n", ts->SMWP_enable); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG=1; - } - else - HX_PROC_SEND_FLAG=0; - - return count; -} - -static ssize_t himax_SMWP_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - - if (buf[0] == '0') - { - ts->SMWP_enable = 0; - } - else if (buf[0] == '1') - { - ts->SMWP_enable = 1; - } - else - return -EINVAL; - - himax_set_SMWP_func(ts->client, ts->SMWP_enable); - HX_SMWP_EN = ts->SMWP_enable; - I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN); - - return len; -} - -static const struct file_operations himax_proc_SMWP_ops = -{ - .owner = THIS_MODULE, - .read = himax_SMWP_read, - .write = himax_SMWP_write, -}; - -static ssize_t himax_GESTURE_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - int i =0; - int ret = 0; - char *temp_buf; - - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - for(i=0;i<16;i++) - ret += snprintf(temp_buf+ret, len-ret, "ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]); - HX_PROC_SEND_FLAG = 1; - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - { - HX_PROC_SEND_FLAG = 0; - ret = 0; - } - return ret; -} - -static ssize_t himax_GESTURE_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - int i =0; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - I("himax_GESTURE_store= %s \n",buf); - for (i=0;i<16;i++) - { - if (buf[i] == '0') - ts->gesture_cust_en[i]= 0; - else if (buf[i] == '1') - ts->gesture_cust_en[i]= 1; - else - ts->gesture_cust_en[i]= 0; - I("gesture en[%d]=%d \n", i, ts->gesture_cust_en[i]); - } - return len; -} - -static const struct file_operations himax_proc_Gesture_ops = -{ - .owner = THIS_MODULE, - .read = himax_GESTURE_read, - .write = himax_GESTURE_write, -}; -#endif - -int himax_touch_proc_init(void) -{ - himax_touch_proc_dir = proc_mkdir( HIMAX_PROC_TOUCH_FOLDER, NULL); - if (himax_touch_proc_dir == NULL) - { - E(" %s: himax_touch_proc_dir file create failed!\n", __func__); - return -ENOMEM; - } - - himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops); - if (himax_proc_debug_level_file == NULL) - { - E(" %s: proc debug_level file create failed!\n", __func__); - goto fail_1; - } - - himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_vendor_ops); - if(himax_proc_vendor_file == NULL) - { - E(" %s: proc vendor file create failed!\n", __func__); - goto fail_2; - } - - himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_attn_ops); - if(himax_proc_attn_file == NULL) - { - E(" %s: proc attn file create failed!\n", __func__); - goto fail_3; - } - - himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops); - if(himax_proc_int_en_file == NULL) - { - E(" %s: proc int en file create failed!\n", __func__); - goto fail_4; - } - - himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops); - if(himax_proc_layout_file == NULL) - { - E(" %s: proc layout file create failed!\n", __func__); - goto fail_5; - } - -#ifdef HX_TP_PROC_RESET - himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, (S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops); - if(himax_proc_reset_file == NULL) - { - E(" %s: proc reset file create failed!\n", __func__); - goto fail_6; - } -#endif - -#ifdef HX_TP_PROC_DIAG - himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops); - if(himax_proc_diag_file == NULL) - { - E(" %s: proc diag file create failed!\n", __func__); - goto fail_7; - } - himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_arrange_ops); - if(himax_proc_diag_arrange_file == NULL) - { - E(" %s: proc diag file create failed!\n", __func__); - goto fail_7_1; - } -#endif - -#ifdef HX_TP_PROC_REGISTER - himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops); - if(himax_proc_register_file == NULL) - { - E(" %s: proc register file create failed!\n", __func__); - goto fail_8; - } -#endif - -#ifdef HX_TP_PROC_DEBUG - himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops); - if(himax_proc_debug_file == NULL) - { - E(" %s: proc debug file create failed!\n", __func__); - goto fail_9; - } -#endif - -#ifdef HX_TP_PROC_FLASH_DUMP - himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops); - if(himax_proc_flash_dump_file == NULL) - { - E(" %s: proc flash dump file create failed!\n", __func__); - goto fail_10; - } -#endif - -#ifdef HX_TP_PROC_SELF_TEST - himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, (S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops); - if(himax_proc_self_test_file == NULL) - { - E(" %s: proc self_test file create failed!\n", __func__); - goto fail_11; - } -#endif - -#ifdef HX_HIGH_SENSE - himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_HSEN_ops); - if(himax_proc_HSEN_file == NULL) - { - E(" %s: proc HSEN file create failed!\n", __func__); - goto fail_12; - } -#endif - -#ifdef HX_SMART_WAKEUP - himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_SMWP_ops); - if(himax_proc_SMWP_file == NULL) - { - E(" %s: proc SMWP file create failed!\n", __func__); - goto fail_13; - } - himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_Gesture_ops); - if(himax_proc_GESTURE_file == NULL) - { - E(" %s: proc GESTURE file create failed!\n", __func__); - goto fail_14; - } -#endif - -#ifdef HX_TP_PROC_SENSE_ON_OFF - himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_sense_on_off_ops); - if(himax_proc_SENSE_ON_OFF_file == NULL) - { - E(" %s: proc SENSE_ON_OFF file create failed!\n", __func__); - goto fail_15; - } -#endif - - return 0 ; - -#ifdef HX_TP_PROC_SENSE_ON_OFF - fail_15: -#endif -#ifdef HX_SMART_WAKEUP - remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); - fail_14: - remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); - fail_13: -#endif -#ifdef HX_HIGH_SENSE - remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); - fail_12: -#endif -#ifdef HX_TP_PROC_SELF_TEST - remove_proc_entry( HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir ); - fail_11: -#endif -#ifdef HX_TP_PROC_FLASH_DUMP - remove_proc_entry( HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir ); - fail_10: -#endif -#ifdef HX_TP_PROC_DEBUG - remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); - fail_9: -#endif -#ifdef HX_TP_PROC_REGISTER - remove_proc_entry( HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir ); - fail_8: -#endif -#ifdef HX_TP_PROC_DIAG - remove_proc_entry( HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir ); - fail_7: - remove_proc_entry( HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir ); - fail_7_1: -#endif -#ifdef HX_TP_PROC_RESET - remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); - fail_6: -#endif - remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); - fail_5: remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); - fail_4: remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); - fail_3: remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); - fail_2: remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); - fail_1: remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); - return -ENOMEM; -} - -void himax_touch_proc_deinit(void) -{ -#ifdef HX_TP_PROC_SENSE_ON_OFF - remove_proc_entry( HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir ); -#endif -#ifdef HX_SMART_WAKEUP - remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); -#endif -#ifdef HX_DOT_VIEW - remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); -#endif -#ifdef HX_TP_PROC_SELF_TEST - remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); -#endif -#ifdef HX_TP_PROC_FLASH_DUMP - remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); -#endif -#ifdef HX_TP_PROC_DEBUG - remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); -#endif -#ifdef HX_TP_PROC_REGISTER - remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); -#endif -#ifdef HX_TP_PROC_DIAG - remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); -#endif -#ifdef HX_TP_PROC_RESET - remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); -#endif - remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); -} -#endif diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.h b/drivers/input/touchscreen/hxchipset/himax_debug.h deleted file mode 100644 index 91a7ae2eb7ab..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_debug.h +++ /dev/null @@ -1,181 +0,0 @@ -/* Himax Android Driver Sample Code for Himax chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_platform.h" -#include "himax_common.h" - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - #define HIMAX_PROC_TOUCH_FOLDER "android_touch" - #define HIMAX_PROC_DEBUG_LEVEL_FILE "debug_level" - #define HIMAX_PROC_VENDOR_FILE "vendor" - #define HIMAX_PROC_ATTN_FILE "attn" - #define HIMAX_PROC_INT_EN_FILE "int_en" - #define HIMAX_PROC_LAYOUT_FILE "layout" - - static struct proc_dir_entry *himax_touch_proc_dir; - static struct proc_dir_entry *himax_proc_debug_level_file; - static struct proc_dir_entry *himax_proc_vendor_file; - static struct proc_dir_entry *himax_proc_attn_file; - static struct proc_dir_entry *himax_proc_int_en_file; - static struct proc_dir_entry *himax_proc_layout_file; - - uint8_t HX_PROC_SEND_FLAG; - -extern int himax_touch_proc_init(void); -extern void himax_touch_proc_deinit(void); -bool getFlashDumpGoing(void); - -#ifdef HX_TP_PROC_REGISTER - #define HIMAX_PROC_REGISTER_FILE "register" - struct proc_dir_entry *himax_proc_register_file; - uint8_t register_command[4]; -#endif - -#ifdef HX_TP_PROC_DIAG - #define HIMAX_PROC_DIAG_FILE "diag" - struct proc_dir_entry *himax_proc_diag_file; - #define HIMAX_PROC_DIAG_ARR_FILE "diag_arr" - struct proc_dir_entry *himax_proc_diag_arrange_file; - -#ifdef HX_TP_PROC_2T2R - static bool Is_2T2R; - static uint8_t x_channel_2; - static uint8_t y_channel_2; - static uint8_t *diag_mutual_2; - - int16_t *getMutualBuffer_2(void); - uint8_t getXChannel_2(void); - uint8_t getYChannel_2(void); - - void setMutualBuffer_2(void); - void setXChannel_2(uint8_t x); - void setYChannel_2(uint8_t y); -#endif - uint8_t x_channel; - uint8_t y_channel; - int16_t *diag_mutual; - int16_t *diag_mutual_new; - int16_t *diag_mutual_old; - uint8_t diag_max_cnt; - - int diag_command; - uint8_t diag_coor[128];// = {0xFF}; - int16_t diag_self[100] = {0}; - - int16_t *getMutualBuffer(void); - int16_t *getMutualNewBuffer(void); - int16_t *getMutualOldBuffer(void); - int16_t *getSelfBuffer(void); - uint8_t getDiagCommand(void); - uint8_t getXChannel(void); - uint8_t getYChannel(void); - - void setMutualBuffer(void); - void setMutualNewBuffer(void); - void setMutualOldBuffer(void); - void setXChannel(uint8_t x); - void setYChannel(uint8_t y); - uint8_t coordinate_dump_enable = 0; - struct file *coordinate_fn; -#endif - -#ifdef HX_TP_PROC_DEBUG - #define HIMAX_PROC_DEBUG_FILE "debug" - struct proc_dir_entry *himax_proc_debug_file = NULL; - - bool fw_update_complete = false; - int handshaking_result = 0; - unsigned char debug_level_cmd = 0; - unsigned char upgrade_fw[128*1024]; -#endif - -#ifdef HX_TP_PROC_FLASH_DUMP - #define HIMAX_PROC_FLASH_DUMP_FILE "flash_dump" - struct proc_dir_entry *himax_proc_flash_dump_file = NULL; - - static int Flash_Size = 131072; - static uint8_t *flash_buffer = NULL; - static uint8_t flash_command = 0; - static uint8_t flash_read_step = 0; - static uint8_t flash_progress = 0; - static uint8_t flash_dump_complete = 0; - static uint8_t flash_dump_fail = 0; - static uint8_t sys_operation = 0; - static uint8_t flash_dump_sector = 0; - static uint8_t flash_dump_page = 0; - static bool flash_dump_going = false; - - static uint8_t getFlashCommand(void); - static uint8_t getFlashDumpComplete(void); - static uint8_t getFlashDumpFail(void); - static uint8_t getFlashDumpProgress(void); - static uint8_t getFlashReadStep(void); - //static uint8_t getFlashDumpSector(void); - //static uint8_t getFlashDumpPage(void); - - void setFlashBuffer(void); - uint8_t getSysOperation(void); - - static void setFlashCommand(uint8_t command); - static void setFlashReadStep(uint8_t step); - static void setFlashDumpComplete(uint8_t complete); - static void setFlashDumpFail(uint8_t fail); - static void setFlashDumpProgress(uint8_t progress); - void setSysOperation(uint8_t operation); - static void setFlashDumpSector(uint8_t sector); - static void setFlashDumpPage(uint8_t page); - static void setFlashDumpGoing(bool going); - -#endif - -#ifdef HX_TP_PROC_SELF_TEST - #define HIMAX_PROC_SELF_TEST_FILE "self_test" - struct proc_dir_entry *himax_proc_self_test_file = NULL; - uint32_t **raw_data_array; - uint8_t X_NUM = 0, Y_NUM = 0; - uint8_t sel_type = 0x0D; -#endif - -#ifdef HX_TP_PROC_RESET -#define HIMAX_PROC_RESET_FILE "reset" -extern void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); -struct proc_dir_entry *himax_proc_reset_file = NULL; -#endif - -#ifdef HX_HIGH_SENSE - #define HIMAX_PROC_HSEN_FILE "HSEN" - struct proc_dir_entry *himax_proc_HSEN_file = NULL; -#endif - -#ifdef HX_TP_PROC_SENSE_ON_OFF - #define HIMAX_PROC_SENSE_ON_OFF_FILE "SenseOnOff" - struct proc_dir_entry *himax_proc_SENSE_ON_OFF_file = NULL; -#endif - -#ifdef HX_RST_PIN_FUNC - void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); -#endif - -#ifdef HX_SMART_WAKEUP -#define HIMAX_PROC_SMWP_FILE "SMWP" -struct proc_dir_entry *himax_proc_SMWP_file = NULL; -#define HIMAX_PROC_GESTURE_FILE "GESTURE" -struct proc_dir_entry *himax_proc_GESTURE_file = NULL; -uint8_t HX_SMWP_EN = 0; -//extern bool FAKE_POWER_KEY_SEND; -#endif - -#endif - diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.c b/drivers/input/touchscreen/hxchipset/himax_ic.c deleted file mode 100644 index 6ad8dc03149b..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_ic.c +++ /dev/null @@ -1,2118 +0,0 @@ -/* Himax Android Driver Sample Code for HMX83100 chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_ic.h" - -static unsigned char i_TP_CRC_FW_128K[]= -{ - #include "HX_CRC_128.i" -}; -static unsigned char i_TP_CRC_FW_64K[]= -{ - #include "HX_CRC_64.i" -}; -static unsigned char i_TP_CRC_FW_124K[]= -{ - #include "HX_CRC_124.i" -}; -static unsigned char i_TP_CRC_FW_60K[]= -{ - #include "HX_CRC_60.i" -}; - - -unsigned long FW_VER_MAJ_FLASH_ADDR; -unsigned long FW_VER_MAJ_FLASH_LENG; -unsigned long FW_VER_MIN_FLASH_ADDR; -unsigned long FW_VER_MIN_FLASH_LENG; -unsigned long CFG_VER_MAJ_FLASH_ADDR; -unsigned long CFG_VER_MAJ_FLASH_LENG; -unsigned long CFG_VER_MIN_FLASH_ADDR; -unsigned long CFG_VER_MIN_FLASH_LENG; - -unsigned char IC_TYPE = 0; -unsigned char IC_CHECKSUM = 0; - -extern struct himax_ic_data* ic_data; - -int himax_hand_shaking(struct i2c_client *client) //0:Running, 1:Stop, 2:I2C Fail -{ - int ret, result; - uint8_t hw_reset_check[1]; - uint8_t hw_reset_check_2[1]; - uint8_t buf0[2]; - uint8_t IC_STATUS_CHECK = 0xAA; - - memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); - memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2)); - - buf0[0] = 0xF2; - if (IC_STATUS_CHECK == 0xAA) { - buf0[1] = 0xAA; - IC_STATUS_CHECK = 0x55; - } else { - buf0[1] = 0x55; - IC_STATUS_CHECK = 0xAA; - } - - ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); - if (ret < 0) { - E("[Himax]:write 0xF2 failed line: %d \n",__LINE__); - goto work_func_send_i2c_msg_fail; - } - msleep(50); - - buf0[0] = 0xF2; - buf0[1] = 0x00; - ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); - if (ret < 0) { - E("[Himax]:write 0x92 failed line: %d \n",__LINE__); - goto work_func_send_i2c_msg_fail; - } - usleep_range(2000, 4000); - - ret = i2c_himax_read(client, 0xD1, hw_reset_check, 1, HIMAX_I2C_RETRY_TIMES); - if (ret < 0) { - E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); - goto work_func_send_i2c_msg_fail; - } - - if ((IC_STATUS_CHECK != hw_reset_check[0])) { - usleep_range(2000, 4000); - ret = i2c_himax_read(client, 0xD1, hw_reset_check_2, 1, HIMAX_I2C_RETRY_TIMES); - if (ret < 0) { - E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); - goto work_func_send_i2c_msg_fail; - } - - if (hw_reset_check[0] == hw_reset_check_2[0]) { - result = 1; - } else { - result = 0; - } - } else { - result = 0; - } - - return result; - -work_func_send_i2c_msg_fail: - return 2; -} - -void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - - if(diag_command != 0) - diag_command = diag_command + 5; - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0x80; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = diag_command; - himax_flash_write_burst(client, tmp_addr, tmp_data); -} - -void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer) -{ - //struct himax_ts_data *ts = container_of(work, struct himax_ts_data, flash_work); - -// uint8_t sector = 0; -// uint8_t page = 0; - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - uint8_t out_buffer[20]; - uint8_t in_buffer[260] = {0}; - int page_prog_start = 0; - int i = 0; - - himax_sense_off(client); - himax_burst_enable(client, 0); - /*=============Dump Flash Start=============*/ - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - for (page_prog_start = 0; page_prog_start < Flash_Size; page_prog_start = page_prog_start + 256) - { - //================================= - // SPI Transfer Control - // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - // Set command : 0x8000_0024 ==> 0x0000_003B - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = 0x00; - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; - tmp_data[2] = (uint8_t)(page_prog_start >> 16); - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //================================== - // AHB_I2C Burst Read - // Set SPI data register : 0x8000_002C ==> 0x00 - //================================== - out_buffer[0] = 0x2C; - out_buffer[1] = 0x00; - out_buffer[2] = 0x00; - out_buffer[3] = 0x80; - i2c_himax_write(client, 0x00 ,out_buffer, 4, 3); - - //================================== - // Read access : 0x0C ==> 0x00 - //================================== - out_buffer[0] = 0x00; - i2c_himax_write(client, 0x0C ,out_buffer, 1, 3); - - //================================== - // Read 128 bytes two times - //================================== - i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); - for (i = 0; i < 128; i++) - flash_buffer[i + page_prog_start] = in_buffer[i]; - - i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); - for (i = 0; i < 128; i++) - flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; - - I("%s:Verify Progress: %x\n", __func__, page_prog_start); - } - -/*=============Dump Flash End=============*/ - //msleep(100); - /* - for( i=0 ; i<8 ;i++) - { - for(j=0 ; j<64 ; j++) - { - setFlashDumpProgress(i*32 + j); - } - } - */ - himax_sense_on(client, 0x01); - - return; - -} - -int himax_chip_self_test(struct i2c_client *client) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[128]; - int pf_value=0x00; - uint8_t test_result_id = 0; - int j; - - memset(tmp_addr, 0x00, sizeof(tmp_addr)); - memset(tmp_data, 0x00, sizeof(tmp_data)); - - himax_interface_on(client); - himax_sense_off(client); - - //Set criteria - himax_burst_enable(client, 1); - - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; - tmp_data[3] = 0x14; tmp_data[2] = 0xC8; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_data[7] = 0x13; tmp_data[6] = 0x60; tmp_data[5] = 0x0A; tmp_data[4] = 0x99; - - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 8); - - //start selftest - // 0x9008_805C ==> 0x0000_0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - himax_sense_on(client, 1); - - msleep(2000); - - himax_sense_off(client); - msleep(20); - - //===================================== - // Read test result ID : 0x9008_8078 ==> 0xA/0xB/0xC/0xF - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x78; - himax_register_read(client, tmp_addr, 1, tmp_data); - - test_result_id = tmp_data[0]; - - I("%s: check test result, test_result_id=%x, test_result=%x\n", __func__ - ,test_result_id,tmp_data[0]); - - if (test_result_id==0xF) { - I("[Himax]: self-test pass\n"); - pf_value = 0x1; - } else { - E("[Himax]: self-test fail\n"); - pf_value = 0x0; - } - himax_burst_enable(client, 1); - - for (j = 0;j < 10; j++){ - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x06; tmp_addr[1] = 0x00; tmp_addr[0] = 0x0C; - himax_register_read(client, tmp_addr, 1, tmp_data); - I("[Himax]: 9006000C = %d\n", tmp_data[0]); - if (tmp_data[0] != 0){ - tmp_data[3] = 0x90; tmp_data[2] = 0x06; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - i2c_himax_read(client, 0x08, tmp_data, 124,HIMAX_I2C_RETRY_TIMES); - }else{ - break; - } - } - - himax_sense_on(client, 1); - msleep(120); - - return pf_value; -} - -void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - - himax_burst_enable(client, 0); - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = HSEN_enable; - himax_flash_write_burst(client, tmp_addr, tmp_data); -} -void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data) -{ - uint8_t tmp_addr[4]; - - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; - himax_register_read(client, tmp_addr, 1, tmp_data); -} - -void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable; - himax_flash_write_burst(client, tmp_addr, tmp_data); -} - -void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data) -{ - uint8_t tmp_addr[4]; - - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; - himax_register_read(client, tmp_addr, 1, tmp_data); -} - -int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte) -{ - uint8_t tmp_data[4]; - - tmp_data[0] = 0x31; - if ( i2c_himax_write(client, 0x13 ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return -EBUSY; - } - - tmp_data[0] = (0x10 | auto_add_4_byte); - if ( i2c_himax_write(client, 0x0D ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return -EBUSY; - } - return 0; - -} - -void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data) -{ - uint8_t tmp_data[4]; - int i = 0; - int address = 0; - - if(read_length>256) - { - E("%s: read len over 256!\n", __func__); - return; - } - if (read_length > 1) - himax_burst_enable(client, 1); - else - himax_burst_enable(client, 0); - address = (read_addr[3] << 24) + (read_addr[2] << 16) + (read_addr[1] << 8) + read_addr[0]; - i = address; - tmp_data[0] = (uint8_t)i; - tmp_data[1] = (uint8_t)(i >> 8); - tmp_data[2] = (uint8_t)(i >> 16); - tmp_data[3] = (uint8_t)(i >> 24); - if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x08 ,read_data, read_length * 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - if (read_length > 1) - himax_burst_enable(client, 0); -} - -void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data) -{ - uint8_t tmpbyte[2]; - - if ( i2c_himax_write(client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - tmpbyte[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x08 ,&read_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x09 ,&read_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x0A ,&read_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x0B ,&read_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x18 ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - }// No bus request - - if ( i2c_himax_read(client, 0x0F ,&tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - }// idle state - -} - -void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data) -{ - uint8_t data_byte[8]; - int i = 0, j = 0; - - for (i = 0; i < 4; i++) - { - data_byte[i] = reg_byte[i]; - } - for (j = 4; j < 8; j++) - { - data_byte[j] = write_data[j-4]; - } - - if ( i2c_himax_write(client, 0x00 ,data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - -} - -int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length) -{ - uint8_t data_byte[256]; - int i = 0, j = 0; - - for (i = 0; i < 4; i++) - { - data_byte[i] = reg_byte[i]; - } - for (j = 4; j < length + 4; j++) - { - data_byte[j] = write_data[j - 4]; - } - - if ( i2c_himax_write(client, 0x00 ,data_byte, length + 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return -EBUSY; - } - - return 0; -} - -int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data) -{ - int i =0, address = 0; - int ret = 0; - - address = (write_addr[3] << 24) + (write_addr[2] << 16) + (write_addr[1] << 8) + write_addr[0]; - - for (i = address; i < address + write_length * 4; i = i + 4) - { - if (write_length > 1) - { - ret = himax_burst_enable(client, 1); - if(ret) - return ret; - } - else - { - ret = himax_burst_enable(client, 0); - if(ret) - return ret; - } - ret = himax_flash_write_burst_lenth(client, write_addr, write_data, write_length * 4); - if(ret < 0) - return ret; - } - - return 0; -} - -void himax_sense_off(struct i2c_client *client) -{ - uint8_t wdt_off = 0x00; - uint8_t tmp_addr[4]; - uint8_t tmp_data[5]; - - himax_burst_enable(client, 0); - - while(wdt_off == 0x00) - { - // 0x9000_800C ==> 0x0000_AC53 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0xAC; tmp_data[0] = 0x53; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Read Watch Dog disable password : 0x9000_800C ==> 0x0000_AC53 - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; - himax_register_read(client, tmp_addr, 1, tmp_data); - - //Check WDT - if (tmp_data[0] == 0x53 && tmp_data[1] == 0xAC && tmp_data[2] == 0x00 && tmp_data[3] == 0x00) - wdt_off = 0x01; - else - wdt_off = 0x00; - } - - // VCOM //0x9008_806C ==> 0x0000_0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x6C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - msleep(20); - - // 0x9000_0010 ==> 0x0000_00DA - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xDA; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Read CPU clock off password : 0x9000_0010 ==> 0x0000_00DA - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - himax_register_read(client, tmp_addr, 1, tmp_data); - I("%s: CPU clock off password data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - -} - -void himax_interface_on(struct i2c_client *client) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[5]; - - //=========================================== - // Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000 - //=========================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - himax_flash_read(client, tmp_addr, tmp_data); //avoid RD/WR fail -} - -bool wait_wip(struct i2c_client *client, int Timing) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - uint8_t in_buffer[10]; - //uint8_t out_buffer[20]; - int retry_cnt = 0; - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - in_buffer[0] = 0x01; - - do - { - //===================================== - // SPI Transfer Control : 0x8000_0020 ==> 0x4200_0003 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x42; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x03; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // SPI Command : 0x8000_0024 ==> 0x0000_0005 - // read 0x8000_002C for 0x01, means wait success - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x05; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - in_buffer[0] = in_buffer[1] = in_buffer[2] = in_buffer[3] = 0xFF; - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; - himax_register_read(client, tmp_addr, 1, in_buffer); - - if ((in_buffer[0] & 0x01) == 0x00) - return true; - - retry_cnt++; - - if (in_buffer[0] != 0x00 || in_buffer[1] != 0x00 || in_buffer[2] != 0x00 || in_buffer[3] != 0x00) - I("%s:Wait wip retry_cnt:%d, buffer[0]=%d, buffer[1]=%d, buffer[2]=%d, buffer[3]=%d \n", __func__, - retry_cnt,in_buffer[0],in_buffer[1],in_buffer[2],in_buffer[3]); - - if (retry_cnt > 100) - { - E("%s: Wait wip error!\n", __func__); - return false; - } - msleep(Timing); - }while ((in_buffer[0] & 0x01) == 0x01); - return true; -} - -void himax_sense_on(struct i2c_client *client, uint8_t FlashMode) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[128]; - - himax_interface_on(client); - himax_burst_enable(client, 0); - //CPU reset - // 0x9000_0014 ==> 0x0000_00CA - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xCA; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Read pull low CPU reset signal : 0x9000_0014 ==> 0x0000_00CA - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - himax_register_read(client, tmp_addr, 1, tmp_data); - - I("%s: check pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - - // 0x9000_0014 ==> 0x0000_0000 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Read revert pull low CPU reset signal : 0x9000_0014 ==> 0x0000_0000 - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - himax_register_read(client, tmp_addr, 1, tmp_data); - - I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - - //===================================== - // Reset TCON - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - usleep_range(10000, 20000); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - if (FlashMode == 0x00) //SRAM - { - //===================================== - // Re-map - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xF1; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); - I("%s:83100_Chip_Re-map ON\n", __func__); - } - else - { - //===================================== - // Re-map off - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); - I("%s:83100_Chip_Re-map OFF\n", __func__); - } - //===================================== - // CPU clock on - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); - -} - -void himax_chip_erase(struct i2c_client *client) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - - himax_burst_enable(client, 0); - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Chip Erase - // Erase Command : 0x8000_0024 ==> 0x0000_00C7 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xC7; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - msleep(2000); - - if (!wait_wip(client, 100)) - E("%s:83100_Chip_Erase Fail\n", __func__); - -} - -bool himax_block_erase(struct i2c_client *client) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - - himax_burst_enable(client, 0); - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Block Erase - // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr - // 0x8000_0020 ==> 0x6700_0000 //control - // 0x8000_0024 ==> 0x0000_0052 //BE - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x52; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - msleep(1000); - - if (!wait_wip(client, 100)) - { - E("%s:83100_Erase Fail\n", __func__); - return false; - } - else - { - return true; - } - -} - -bool himax_sector_erase(struct i2c_client *client, int start_addr) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - int page_prog_start = 0; - - himax_burst_enable(client, 0); - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - for (page_prog_start = start_addr; page_prog_start < start_addr + 0x0F000; page_prog_start = page_prog_start + 0x1000) - { - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Sector Erase - // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr - // 0x8000_0020 ==> 0x6700_0000 //control - // 0x8000_0024 ==> 0x0000_0020 //SE - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x20; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - msleep(200); - - if (!wait_wip(client, 100)) - { - E("%s:83100_Erase Fail\n", __func__); - return false; - } - } - return true; -} - -void himax_sram_write(struct i2c_client *client, uint8_t *FW_content) -{ - int i = 0; - uint8_t tmp_addr[4]; - uint8_t tmp_data[128]; - int FW_length = 0x4000; // 0x4000 = 16K bin file - - //himax_sense_off(client); - - for (i = 0; i < FW_length; i = i + 128) - { - himax_burst_enable(client, 1); - - if (i < 0x100) - { - tmp_addr[3] = 0x08; - tmp_addr[2] = 0x00; - tmp_addr[1] = 0x00; - tmp_addr[0] = i; - } - else if (i >= 0x100 && i < 0x10000) - { - tmp_addr[3] = 0x08; - tmp_addr[2] = 0x00; - tmp_addr[1] = (i >> 8); - tmp_addr[0] = i; - } - - memcpy(&tmp_data[0], &FW_content[i], 128); - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 128); - - } - - if (!wait_wip(client, 100)) - E("%s:83100_Sram_Write Fail\n", __func__); -} - -bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size) -{ - int i = 0; - uint8_t out_buffer[20]; - uint8_t in_buffer[128]; - uint8_t *get_fw_content; - - get_fw_content = kzalloc(0x4000*sizeof(uint8_t), GFP_KERNEL); - if (!get_fw_content) - return false; - - for (i = 0; i < 0x4000; i = i + 128) - { - himax_burst_enable(client, 1); - - //================================== - // AHB_I2C Burst Read - //================================== - if (i < 0x100) - { - out_buffer[3] = 0x08; - out_buffer[2] = 0x00; - out_buffer[1] = 0x00; - out_buffer[0] = i; - } - else if (i >= 0x100 && i < 0x10000) - { - out_buffer[3] = 0x08; - out_buffer[2] = 0x00; - out_buffer[1] = (i >> 8); - out_buffer[0] = i; - } - - if ( i2c_himax_write(client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return false; - } - - out_buffer[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return false; - } - - if ( i2c_himax_read(client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return false; - } - memcpy(&get_fw_content[i], &in_buffer[0], 128); - } - - for (i = 0; i < FW_Size; i++) - { - if (FW_File[i] != get_fw_content[i]) - { - E("%s: fail! SRAM[%x]=%x NOT CRC_ifile=%x\n", __func__,i,get_fw_content[i],FW_File[i]); - return false; - } - } - - kfree(get_fw_content); - - return true; -} - -void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size) -{ - int page_prog_start = 0; - int program_length = 48; - int i = 0, j = 0, k = 0; - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - uint8_t buring_data[256]; // Read for flash data, 128K - // 4 bytes for 0x80002C padding - - //himax_interface_on(client); - himax_burst_enable(client, 0); - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) - { - //msleep(5); - //===================================== - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //================================= - // SPI Transfer Control - // Set 256 bytes page write : 0x8000_0020 ==> 0x610F_F000 - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x61; tmp_data[2] = 0x0F; tmp_data[1] = 0xF0; tmp_data[0] = 0x00; - // data bytes should be 0x6100_0000 + ((word_number)*4-1)*4096 = 0x6100_0000 + 0xFF000 = 0x610F_F000 - // Programmable size = 1 page = 256 bytes, word_number = 256 byte / 4 = 64 - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - //tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; // Flash start address 1st : 0x0000_0000 - - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = 0x00; - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; - tmp_data[2] = (uint8_t)(page_prog_start >> 16); - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - - himax_flash_write_burst(client, tmp_addr, tmp_data); - - - //================================= - // Send 16 bytes data : 0x8000_002C ==> 16 bytes data - //================================= - buring_data[0] = 0x2C; - buring_data[1] = 0x00; - buring_data[2] = 0x00; - buring_data[3] = 0x80; - - for (i = /*0*/page_prog_start, j = 0; i < 16 + page_prog_start/**/; i++, j++) /// <------ bin file - { - buring_data[j + 4] = FW_content[i]; - } - - - if ( i2c_himax_write(client, 0x00 ,buring_data, 20, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - //================================= - // Write command : 0x8000_0024 ==> 0x0000_0002 - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x02; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //================================= - // Send 240 bytes data : 0x8000_002C ==> 240 bytes data - //================================= - - for (j = 0; j < 5; j++) - { - for (i = (page_prog_start + 16 + (j * 48)), k = 0; i < (page_prog_start + 16 + (j * 48)) + program_length; i++, k++) /// <------ bin file - { - buring_data[k+4] = FW_content[i];//(byte)i; - } - - if ( i2c_himax_write(client, 0x00 ,buring_data, program_length+4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - } - - if (!wait_wip(client, 1)) - E("%s:83100_Flash_Programming Fail\n", __func__); - } -} - -bool himax_check_chip_version(struct i2c_client *client) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - uint8_t ret_data = 0x00; - int i = 0; - int ret = 0; - himax_sense_off(client); - for (i = 0; i < 5; i++) - { - // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - ret = himax_register_write(client, tmp_addr, 1, tmp_data); - if(ret) - return false; - - // 2. Set bank as 0 (0x8001_BD01 = 0x0000_0000) - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xBD; tmp_addr[0] = 0x01; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - ret = himax_register_write(client, tmp_addr, 1, tmp_data); - if(ret) - return false; - - // 3. Read driver ID register RF4H 1 byte (0x8001_F401) - // Driver register RF4H 1 byte value = 0x84H, read back value will become 0x84848484 - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xF4; tmp_addr[0] = 0x01; - himax_register_read(client, tmp_addr, 1, tmp_data); - ret_data = tmp_data[0]; - - I("%s:Read driver IC ID = %X\n", __func__, ret_data); - if (ret_data == 0x84) - { - IC_TYPE = HX_83100_SERIES_PWON; - //himax_sense_on(client, 0x01); - ret_data = true; - break; - } - else - { - ret_data = false; - E("%s:Read driver ID register Fail:\n", __func__); - } - } - // 4. After read finish, set DDREG_Req = 0 (0x9000_0020 = 0x0000_0000) (Unlock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_register_write(client, tmp_addr, 1, tmp_data); - //himax_sense_on(client, 0x01); - return ret_data; -} - -#if 1 -int himax_check_CRC(struct i2c_client *client, int mode) -{ - bool burnFW_success = false; - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - int tmp_value; - int CRC_value = 0; - - memset(tmp_data, 0x00, sizeof(tmp_data)); - - if (1) - { - if(mode == fw_image_60k) - { - himax_sram_write(client, (i_TP_CRC_FW_60K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_60K, 0x4000); - } - else if(mode == fw_image_64k) - { - himax_sram_write(client, (i_TP_CRC_FW_64K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_64K, 0x4000); - } - else if(mode == fw_image_124k) - { - himax_sram_write(client, (i_TP_CRC_FW_124K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_124K, 0x4000); - } - else if(mode == fw_image_128k) - { - himax_sram_write(client, (i_TP_CRC_FW_128K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_128K, 0x4000); - } - if (burnFW_success) - { - I("%s: Start to do CRC FW mode=%d \n", __func__,mode); - himax_sense_on(client, 0x00); // run CRC firmware - - while(true) - { - msleep(100); - - tmp_addr[3] = 0x90; - tmp_addr[2] = 0x08; - tmp_addr[1] = 0x80; - tmp_addr[0] = 0x94; - himax_register_read(client, tmp_addr, 1, tmp_data); - - I("%s: CRC from firmware is %x, %x, %x, %x \n", __func__,tmp_data[3], - tmp_data[2],tmp_data[1],tmp_data[0]); - - if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF) - { - } - else - break; - } - - CRC_value = tmp_data[3]; - - tmp_value = tmp_data[2] << 8; - CRC_value += tmp_value; - - tmp_value = tmp_data[1] << 16; - CRC_value += tmp_value; - - tmp_value = tmp_data[0] << 24; - CRC_value += tmp_value; - - I("%s: CRC Value is %x \n", __func__, CRC_value); - - //Close Remapping - //===================================== - // Re-map close - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); - return CRC_value; - } - else - { - E("%s: SRAM write fail\n", __func__); - return 0; - } - } - else - I("%s: NO CRC Check File \n", __func__); - - return 0; -} - -bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode) -{ - uint8_t tmp_data[4]; - int i, j; - int fw_data; - int fw_data_2; - int CRC = 0xFFFFFFFF; - int PolyNomial = 0x82F63B78; - int length = 0; - - if (mode == fw_image_128k) - length = 0x8000; - else if (mode == fw_image_124k) - length = 0x7C00; - else if (mode == fw_image_64k) - length = 0x4000; - else //if (mode == fw_image_60k) - length = 0x3C00; - - for (i = 0; i < length; i++) - { - fw_data = FW_content[i * 4 ]; - - for (j = 1; j < 4; j++) - { - fw_data_2 = FW_content[i * 4 + j]; - fw_data += (fw_data_2) << (8 * j); - } - - CRC = fw_data ^ CRC; - - for (j = 0; j < 32; j++) - { - if ((CRC % 2) != 0) - { - CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; - } - else - { - CRC = (((CRC >> 1) ^ 0x7FFFFFFF)& 0x7FFFFFFF); - } - } - } - - I("%s: CRC calculate from bin file is %x \n", __func__, CRC); - - tmp_data[0] = (uint8_t)(CRC >> 24); - tmp_data[1] = (uint8_t)(CRC >> 16); - tmp_data[2] = (uint8_t)(CRC >> 8); - tmp_data[3] = (uint8_t) CRC; - - CRC = tmp_data[0]; - CRC += tmp_data[1] << 8; - CRC += tmp_data[2] << 16; - CRC += tmp_data[3] << 24; - - I("%s: CRC calculate from bin file REVERSE %x \n", __func__, CRC); - I("%s: CRC calculate from FWis %x \n", __func__, CRC_from_FW); - if (CRC_from_FW == CRC) - return true; - else - return false; -} -#endif - -int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) -{ - int CRC_from_FW = 0; - int burnFW_success = 0; - - if (len != 0x10000) //64k - { - E("%s: The file size is not 64K bytes\n", __func__); - return false; - } - himax_sense_off(client); - msleep(500); - himax_interface_on(client); - if (!himax_sector_erase(client, 0x00000)) - { - E("%s:Sector erase fail!Please restart the IC.\n", __func__); - return false; - } - himax_flash_programming(client, fw, 0x0F000); - - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; - - CRC_from_FW = himax_check_CRC(client,fw_image_60k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_60k); - //himax_sense_on(client, 0x01); - return burnFW_success; -} - -int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) -{ - int CRC_from_FW = 0; - int burnFW_success = 0; - - if (len != 0x10000) //64k - { - E("%s: The file size is not 64K bytes\n", __func__); - return false; - } - himax_sense_off(client); - msleep(500); - himax_interface_on(client); - himax_chip_erase(client); - himax_flash_programming(client, fw, len); - - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; - - CRC_from_FW = himax_check_CRC(client,fw_image_64k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_64k); - //himax_sense_on(client, 0x01); - return burnFW_success; -} - -int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) -{ - int CRC_from_FW = 0; - int burnFW_success = 0; - - if (len != 0x20000) //128k - { - E("%s: The file size is not 128K bytes\n", __func__); - return false; - } - himax_sense_off(client); - msleep(500); - himax_interface_on(client); - if (!himax_block_erase(client)) - { - E("%s:Block erase fail!Please restart the IC.\n", __func__); - return false; - } - - if (!himax_sector_erase(client, 0x10000)) - { - E("%s:Sector erase fail!Please restart the IC.\n", __func__); - return false; - } - himax_flash_programming(client, fw, 0x1F000); - - - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; - - CRC_from_FW = himax_check_CRC(client,fw_image_124k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_124k); - //himax_sense_on(client, 0x01); - return burnFW_success; -} - -int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) -{ - int CRC_from_FW = 0; - int burnFW_success = 0; - - if (len != 0x20000) //128k - { - E("%s: The file size is not 128K bytes\n", __func__); - return false; - } - himax_sense_off(client); - msleep(500); - himax_interface_on(client); - himax_chip_erase(client); - - himax_flash_programming(client, fw, len); - - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; - - CRC_from_FW = himax_check_CRC(client,fw_image_128k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_128k); - //himax_sense_on(client, 0x01); - return burnFW_success; -} - -void himax_touch_information(struct i2c_client *client) -{ - uint8_t cmd[4]; - char data[12] = {0}; - - I("%s:IC_TYPE =%d\n", __func__,IC_TYPE); - - if(IC_TYPE == HX_83100_SERIES_PWON) - { - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xF8; - himax_register_read(client, cmd, 1, data); - - ic_data->HX_RX_NUM = data[1]; - ic_data->HX_TX_NUM = data[2]; - ic_data->HX_MAX_PT = data[3]; - - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xFC; - himax_register_read(client, cmd, 1, data); - - if((data[1] & 0x04) == 0x04) { - ic_data->HX_XY_REVERSE = true; - } else { - ic_data->HX_XY_REVERSE = false; - } - ic_data->HX_Y_RES = data[3]*256; - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x01; cmd[0] = 0x00; - himax_register_read(client, cmd, 1, data); - ic_data->HX_Y_RES = ic_data->HX_Y_RES + data[0]; - ic_data->HX_X_RES = data[1]*256 + data[2]; - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x8C; - himax_register_read(client, cmd, 1, data); - if((data[0] & 0x01) == 1) { - ic_data->HX_INT_IS_EDGE = true; - } else { - ic_data->HX_INT_IS_EDGE = false; - } - if (ic_data->HX_RX_NUM > 40) - ic_data->HX_RX_NUM = 29; - if (ic_data->HX_TX_NUM > 20) - ic_data->HX_TX_NUM = 16; - if (ic_data->HX_MAX_PT > 10) - ic_data->HX_MAX_PT = 10; - if (ic_data->HX_Y_RES > 2000) - ic_data->HX_Y_RES = 1280; - if (ic_data->HX_X_RES > 2000) - ic_data->HX_X_RES = 720; -#ifdef HX_EN_MUT_BUTTON - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xE8; - himax_register_read(client, cmd, 1, data); - ic_data->HX_BT_NUM = data[3]; -#endif - I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d \n", __func__,ic_data->HX_RX_NUM,ic_data->HX_TX_NUM,ic_data->HX_MAX_PT); - I("%s:HX_XY_REVERSE =%d,HX_Y_RES =%d,HX_X_RES=%d \n", __func__,ic_data->HX_XY_REVERSE,ic_data->HX_Y_RES,ic_data->HX_X_RES); - I("%s:HX_INT_IS_EDGE =%d \n", __func__,ic_data->HX_INT_IS_EDGE); - } - else - { - ic_data->HX_RX_NUM = 0; - ic_data->HX_TX_NUM = 0; - ic_data->HX_BT_NUM = 0; - ic_data->HX_X_RES = 0; - ic_data->HX_Y_RES = 0; - ic_data->HX_MAX_PT = 0; - ic_data->HX_XY_REVERSE = false; - ic_data->HX_INT_IS_EDGE = false; - } -} - -void himax_read_FW_ver(struct i2c_client *client) -{ - uint8_t cmd[4]; - uint8_t data[64] = {0}; - - //===================================== - // Read FW version : 0x0000_E303 - //===================================== - cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x00; - himax_register_read(client, cmd, 1, data); - - ic_data->vendor_config_ver = data[3]<<8; - - cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x04; - himax_register_read(client, cmd, 1, data); - - ic_data->vendor_config_ver = data[0] | ic_data->vendor_config_ver; - I("CFG_VER : %X \n",ic_data->vendor_config_ver); - - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x28; - himax_register_read(client, cmd, 1, data); - - ic_data->vendor_fw_ver = data[0]<<8 | data[1]; - I("FW_VER : %X \n",ic_data->vendor_fw_ver); - - - return; -} - -bool himax_ic_package_check(struct i2c_client *client) -{ -#if 0 - uint8_t cmd[3]; - uint8_t data[3]; - - memset(cmd, 0x00, sizeof(cmd)); - memset(data, 0x00, sizeof(data)); - - if (i2c_himax_read(client, 0xD1, cmd, 3, HIMAX_I2C_RETRY_TIMES) < 0) - return false ; - - if (i2c_himax_read(client, 0x31, data, 3, HIMAX_I2C_RETRY_TIMES) < 0) - return false; - - if((data[0] == 0x85 && data[1] == 0x29)) - { - IC_TYPE = HX_85XX_F_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 64901; //0xFD85 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 64902; //0xFD86 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 64928; //0xFDA0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 64940; //0xFDAC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x F\n"); - } - if((data[0] == 0x85 && data[1] == 0x30) || (cmd[0] == 0x05 && cmd[1] == 0x85 && cmd[2] == 0x29)) - { - IC_TYPE = HX_85XX_E_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; //0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x E\n"); - } - else if((data[0] == 0x85 && data[1] == 0x31)) - { - IC_TYPE = HX_85XX_ES_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; //0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x ES\n"); - } - else if ((data[0] == 0x85 && data[1] == 0x28) || (cmd[0] == 0x04 && cmd[1] == 0x85 && - (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28))) { - IC_TYPE = HX_85XX_D_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; // 0x00A0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; // 0x00AC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x D\n"); - } else if ((data[0] == 0x85 && data[1] == 0x23) || (cmd[0] == 0x03 && cmd[1] == 0x85 && - (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28 || cmd[2] == 0x29))) { - IC_TYPE = HX_85XX_C_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 135; // 0x0087 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 147; // 0x0093 - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x C\n"); - } else if ((data[0] == 0x85 && data[1] == 0x26) || - (cmd[0] == 0x02 && cmd[1] == 0x85 && - (cmd[2] == 0x19 || cmd[2] == 0x25 || cmd[2] == 0x26))) { - IC_TYPE = HX_85XX_B_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 728; // 0x02D8 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 692; // 0x02B4 - CFG_VER_MAJ_FLASH_LENG = 3; - CFG_VER_MIN_FLASH_ADDR = 704; // 0x02C0 - CFG_VER_MIN_FLASH_LENG = 3; - I("Himax IC package 852x B\n"); - } else if ((data[0] == 0x85 && data[1] == 0x20) || (cmd[0] == 0x01 && - cmd[1] == 0x85 && cmd[2] == 0x19)) { - IC_TYPE = HX_85XX_A_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; - I("Himax IC package 852x A\n"); - } else { - E("Himax IC package incorrect!!\n"); - }*/ -#else - IC_TYPE = HX_83100_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 57384; //0xE028 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 57385; //0xE029 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 58115; //0xE303 - CFG_VER_MAJ_FLASH_LENG = 1; - CFG_VER_MIN_FLASH_ADDR = 58116; //0xE304 - CFG_VER_MIN_FLASH_LENG = 1; - I("Himax IC package 83100_in\n"); - -#endif - return true; -} - -void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length) -{ - uint8_t cmd[4]; - - cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - - cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - - i2c_himax_read(client, 0x08, buf, length, HIMAX_I2C_RETRY_TIMES); -} - -#if 0 -static void himax_83100_Flash_Write(uint8_t * reg_byte, uint8_t * write_data) -{ - uint8_t tmpbyte[2]; - - if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if (isBusrtOn == false) - { - tmpbyte[0] = 0x01; - if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - } -} -#endif -#if 0 -static void himax_83100_Flash_Burst_Write(uint8_t * reg_byte, uint8_t * write_data) -{ - //uint8_t tmpbyte[2]; - int i = 0; - - if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - // Write 256 bytes with continue burst mode - for (i = 0; i < 256; i = i + 4) - { - if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[i+1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[i+2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[i+3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - } - - //if (isBusrtOn == false) - //{ - // tmpbyte[0] = 0x01; - // if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, 3) < 0) { - // E("%s: i2c access fail!\n", __func__); - // return; - // } - //} - -} -#endif - -#if 0 -static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - uint8_t out_buffer[20]; - uint8_t in_buffer[260]; - - int fail_addr=0, fail_cnt=0; - int page_prog_start = 0; - int i = 0; - - himax_interface_on(private_ts->client); - himax_burst_enable(private_ts->client, 0); - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_83100_Flash_Write(tmp_addr, tmp_data); - - for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) - { - //================================= - // SPI Transfer Control - // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - // Set command : 0x8000_0024 ==> 0x0000_003B - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; - himax_83100_Flash_Write(tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = 0x00; - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; - tmp_data[2] = (uint8_t)(page_prog_start >> 16); - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - himax_83100_Flash_Write(tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; - himax_83100_Flash_Write(tmp_addr, tmp_data); - - //================================== - // AHB_I2C Burst Read - // Set SPI data register : 0x8000_002C ==> 0x00 - //================================== - out_buffer[0] = 0x2C; - out_buffer[1] = 0x00; - out_buffer[2] = 0x00; - out_buffer[3] = 0x80; - i2c_himax_write(private_ts->client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES); - - //================================== - // Read access : 0x0C ==> 0x00 - //================================== - out_buffer[0] = 0x00; - i2c_himax_write(private_ts->client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES); - - //================================== - // Read 128 bytes two times - //================================== - i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); - for (i = 0; i < 128; i++) - flash_buffer[i + page_prog_start] = in_buffer[i]; - - i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); - for (i = 0; i < 128; i++) - flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; - - //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; - //himax_register_read(tmp_addr, 32, out in_buffer); - //for (int i = 0; i < 128; i++) - // flash_buffer[i + page_prog_start] = in_buffer[i]; - //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; - //himax_register_read(tmp_addr, 32, out in_buffer); - //for (int i = 0; i < 128; i++) - // flash_buffer[i + page_prog_start] = in_buffer[i]; - - I("%s:Verify Progress: %x\n", __func__, page_prog_start); - } - - fail_cnt = 0; - for (i = 0; i < FW_Size; i++) - { - if (FW_File[i] != flash_buffer[i]) - { - if (fail_cnt == 0) - fail_addr = i; - - fail_cnt++; - //E("%s Fail Block:%x\n", __func__, i); - //return false; - } - } - if (fail_cnt > 0) - { - E("%s:Start Fail Block:%x and fail block count=%x\n" , __func__,fail_addr,fail_cnt); - return false; - } - - I("%s:Byte read verify pass.\n", __func__); - return true; - -} -#endif - -void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data) -{ - int i; - int cnt = 0; - unsigned char tmp_addr[4]; - unsigned char tmp_data[4]; - uint8_t max_i2c_size = 32; - int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; - int total_size_4bytes = total_size / 4; - int total_read_times = 0; - unsigned long address = 0x08000468; - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x5A; tmp_data[0] = 0xA5; - himax_flash_write_burst(client, tmp_addr, tmp_data); - do - { - cnt++; - himax_register_read(client, tmp_addr, 1, tmp_data); - usleep_range(10000, 20000); - } while ((tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A) && cnt < 100); - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x68; - if (total_size_4bytes % max_i2c_size == 0) - { - total_read_times = total_size_4bytes / max_i2c_size; - } - else - { - total_read_times = total_size_4bytes / max_i2c_size + 1; - } - for (i = 0; i < (total_read_times); i++) - { - if ( total_size_4bytes >= max_i2c_size) - { - himax_register_read(client, tmp_addr, max_i2c_size, &info_data[i*max_i2c_size*4]); - total_size_4bytes = total_size_4bytes - max_i2c_size; - } - else - { - himax_register_read(client, tmp_addr, total_size_4bytes % max_i2c_size, &info_data[i*max_i2c_size*4]); - } - address += max_i2c_size*4; - tmp_addr[1] = (uint8_t)((address>>8)&0x00FF); - tmp_addr[0] = (uint8_t)((address)&0x00FF); - } - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; - tmp_data[3] = 0x11; tmp_data[2] = 0x22; tmp_data[1] = 0x33; tmp_data[0] = 0x44; - himax_flash_write_burst(client, tmp_addr, tmp_data); -} -//ts_work -int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max){ - int RawDataLen; - if (raw_cnt_rmd != 0x00) { - RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+3)*4) - 1; - }else{ - RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+2)*4) - 1; - } - return RawDataLen; -} - -bool read_event_stack(struct i2c_client *client, uint8_t *buf, int length) -{ - uint8_t cmd[4]; - - if(length > 56) - length = 124; - //===================== - //AHB I2C Burst Read - //===================== - cmd[0] = 0x31; - if ( i2c_himax_write(client, 0x13 ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - goto err_workqueue_out; - } - - cmd[0] = 0x10; - if ( i2c_himax_write(client, 0x0D ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - goto err_workqueue_out; - } - //===================== - //Read event stack - //===================== - cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - goto err_workqueue_out; - } - - cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - goto err_workqueue_out; - } - i2c_himax_read(client, 0x08, buf, length,HIMAX_I2C_RETRY_TIMES); - return 1; - - err_workqueue_out: - return 0; -} - -bool post_read_event_stack(struct i2c_client *client) -{ - return 1; -} -bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf) //return checksum value -{ - uint16_t check_sum_cal = 0; - int i; - - //Check 124th byte CRC - for (i = hx_touch_info_size, check_sum_cal = 0; i < 124; i=i+2) - { - check_sum_cal += (buf[i+1]*256 + buf[i]); - } - if (check_sum_cal % 0x10000 != 0) - { - I("%s: diag check sum fail! check_sum_cal=%X, hx_touch_info_size=%d, \n",__func__,check_sum_cal, hx_touch_info_size); - return 0; - } - return 1; -} - - -void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data) -{ - int RawDataLen_word; - int index = 0; - int temp1, temp2,i; - - if (buf[hx_touch_info_size] == 0x3A && buf[hx_touch_info_size+1] == 0xA3 && buf[hx_touch_info_size+2] > 0 && buf[hx_touch_info_size+3] == diag_cmd+5 ) - { - RawDataLen_word = RawDataLen/2; - index = (buf[hx_touch_info_size+2] - 1) * RawDataLen_word; - //I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); - for (i = 0; i < RawDataLen_word; i++) - { - temp1 = index + i; - - if (temp1 < mul_num) - { //mutual - mutual_data[index + i] = buf[i*2 + hx_touch_info_size+4+1]*256 + buf[i*2 + hx_touch_info_size+4]; //4: RawData Header, 1:HSB - } - else - {//self - temp1 = i + index; - temp2 = self_num + mul_num; - - if (temp1 >= temp2) - { - break; - } - - self_data[i+index-mul_num] = buf[i*2 + hx_touch_info_size+4]; //4: RawData Header - self_data[i+index-mul_num+1] = buf[i*2 + hx_touch_info_size+4+1]; - } - } - } - else - { - I("[HIMAX TP MSG]%s: header format is wrong!\n", __func__); - I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); - } -} diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.h b/drivers/input/touchscreen/hxchipset/himax_ic.h deleted file mode 100644 index 18cd12b8b36f..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_ic.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Himax Android Driver Sample Code for HMX83100 chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_platform.h" -#include "himax_common.h" - -#include - - -#define HX_85XX_A_SERIES_PWON 1 -#define HX_85XX_B_SERIES_PWON 2 -#define HX_85XX_C_SERIES_PWON 3 -#define HX_85XX_D_SERIES_PWON 4 -#define HX_85XX_E_SERIES_PWON 5 -#define HX_85XX_ES_SERIES_PWON 6 -#define HX_85XX_F_SERIES_PWON 7 -#define HX_83100_SERIES_PWON 8 - -#define HX_TP_BIN_CHECKSUM_SW 1 -#define HX_TP_BIN_CHECKSUM_HW 2 -#define HX_TP_BIN_CHECKSUM_CRC 3 - -enum fw_image_type { - fw_image_60k = 0x01, - fw_image_64k, - fw_image_124k, - fw_image_128k, -}; - -int himax_hand_shaking(struct i2c_client *client); -void himax_set_SMWP_enable(struct i2c_client *client,uint8_t SMWP_enable); -void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data); -void himax_set_HSEN_enable(struct i2c_client *client,uint8_t HSEN_enable); -void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data); -void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command); -void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer); -int himax_chip_self_test(struct i2c_client *client); -int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte); ////himax_83100_BURST_INC0_EN -void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data); ////RegisterRead83100 -void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data); ////himax_83100_Flash_Read -void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data); ////himax_83100_Flash_Write_Burst -int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length); ////himax_83100_Flash_Write_Burst_lenth -int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data); ////RegisterWrite83100 -void himax_sense_off(struct i2c_client *client); ////himax_83100_SenseOff -void himax_interface_on(struct i2c_client *client); ////himax_83100_Interface_on -bool wait_wip(struct i2c_client *client, int Timing); -void himax_sense_on(struct i2c_client *client, uint8_t FlashMode); ////himax_83100_SenseOn -void himax_chip_erase(struct i2c_client *client); ////himax_83100_Chip_Erase -bool himax_block_erase(struct i2c_client *client); ////himax_83100_Block_Erase -bool himax_sector_erase(struct i2c_client *client, int start_addr); ////himax_83100_Sector_Erase -void himax_sram_write(struct i2c_client *client, uint8_t *FW_content); ////himax_83100_Sram_Write -bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size); ////himax_83100_Sram_Verify -void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size); ////himax_83100_Flash_Programming -bool himax_check_chip_version(struct i2c_client *client); ////himax_83100_CheckChipVersion -int himax_check_CRC(struct i2c_client *client, int mode); ////himax_83100_Check_CRC -bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode); -int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -void himax_touch_information(struct i2c_client *client); -void himax_read_FW_ver(struct i2c_client *client); -bool himax_ic_package_check(struct i2c_client *client); -void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length); -int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max); -bool read_event_stack(struct i2c_client *client, uint8_t *buf_ts, int length); -bool post_read_event_stack(struct i2c_client *client); -bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf_ts); //return checksum value -void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf_ts, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data); -void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data); \ No newline at end of file diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c deleted file mode 100644 index 7e8a1d6572c5..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_platform.c +++ /dev/null @@ -1,796 +0,0 @@ -/* Himax Android Driver Sample Code for HIMAX chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_platform.h" -#include "himax_common.h" - -int irq_enable_count = 0; -#ifdef HX_SMART_WAKEUP -#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) -#endif - -#define PINCTRL_STATE_ACTIVE "pmx_ts_active" -#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" -#define PINCTRL_STATE_RELEASE "pmx_ts_release" - -extern struct himax_ic_data* ic_data; -extern void himax_ts_work(struct himax_ts_data *ts); -extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); -extern int himax_ts_init(struct himax_ts_data *ts); - -extern int tp_rst_gpio; - -#ifdef HX_TP_PROC_DIAG -extern uint8_t getDiagCommand(void); -#endif - -void himax_vk_parser(struct device_node *dt, - struct himax_i2c_platform_data *pdata) -{ - u32 data = 0; - uint8_t cnt = 0, i = 0; - uint32_t coords[4] = {0}; - struct device_node *node, *pp = NULL; - struct himax_virtual_key *vk; - - node = of_parse_phandle(dt, "virtualkey", 0); - if (node == NULL) { - I(" DT-No vk info in DT"); - return; - } else { - while ((pp = of_get_next_child(node, pp))) - cnt++; - if (!cnt) - return; - - vk = kzalloc(cnt * (sizeof *vk), GFP_KERNEL); - if (!vk) - return; - pp = NULL; - while ((pp = of_get_next_child(node, pp))) { - if (of_property_read_u32(pp, "idx", &data) == 0) - vk[i].index = data; - if (of_property_read_u32_array(pp, "range", coords, 4) == 0) { - vk[i].x_range_min = coords[0], vk[i].x_range_max = coords[1]; - vk[i].y_range_min = coords[2], vk[i].y_range_max = coords[3]; - } else - I(" range faile"); - i++; - } - pdata->virtual_key = vk; - for (i = 0; i < cnt; i++) - I(" vk[%d] idx:%d x_min:%d, y_max:%d", i,pdata->virtual_key[i].index, - pdata->virtual_key[i].x_range_min, pdata->virtual_key[i].y_range_max); - } -} - -int himax_parse_dt(struct himax_ts_data *ts, - struct himax_i2c_platform_data *pdata) -{ - int rc, coords_size = 0; - uint32_t coords[4] = {0}; - struct property *prop; - struct device_node *dt = ts->client->dev.of_node; - u32 data = 0; - - prop = of_find_property(dt, "himax,panel-coords", NULL); - if (prop) { - coords_size = prop->length / sizeof(u32); - if (coords_size != 4) - D(" %s:Invalid panel coords size %d", __func__, coords_size); - } - - if (of_property_read_u32_array(dt, "himax,panel-coords", coords, coords_size) == 0) { - pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1]; - pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3]; - I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min, - pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max); - } - - prop = of_find_property(dt, "himax,display-coords", NULL); - if (prop) { - coords_size = prop->length / sizeof(u32); - if (coords_size != 4) - D(" %s:Invalid display coords size %d", __func__, coords_size); - } - rc = of_property_read_u32_array(dt, "himax,display-coords", coords, coords_size); - if (rc && (rc != -EINVAL)) { - D(" %s:Fail to read display-coords %d\n", __func__, rc); - return rc; - } - pdata->screenWidth = coords[1]; - pdata->screenHeight = coords[3]; - I(" DT-%s:display-coords = (%d, %d)", __func__, pdata->screenWidth, - pdata->screenHeight); - - pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); - if (!gpio_is_valid(pdata->gpio_irq)) { - I(" DT:gpio_irq value is not valid\n"); - } - - pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); - if (!gpio_is_valid(pdata->gpio_reset)) { - I(" DT:gpio_rst value is not valid\n"); - } - pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); - if (!gpio_is_valid(pdata->gpio_3v3_en)) { - I(" DT:gpio_3v3_en value is not valid\n"); - } - I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); - - if (of_property_read_u32(dt, "report_type", &data) == 0) { - pdata->protocol_type = data; - I(" DT:protocol_type=%d", pdata->protocol_type); - } - - himax_vk_parser(dt, pdata); - - return 0; -} - -int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) -{ - int retry; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &command, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = length, - .buf = data, - } - }; - - for (retry = 0; retry < toRetry; retry++) { - if (i2c_transfer(client->adapter, msg, 2) == 2) - break; - msleep(20); - } - if (retry == toRetry) { - E("%s: i2c_read_block retry over %d\n", - __func__, toRetry); - return -EIO; - } - return 0; - -} - -int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) -{ - int retry/*, loop_i*/; - uint8_t buf[length + 1]; - - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .len = length + 1, - .buf = buf, - } - }; - - buf[0] = command; - memcpy(buf+1, data, length); - - for (retry = 0; retry < toRetry; retry++) { - if (i2c_transfer(client->adapter, msg, 1) == 1) - break; - msleep(20); - } - - if (retry == toRetry) { - E("%s: i2c_write_block retry over %d\n", - __func__, toRetry); - return -EIO; - } - return 0; - -} - -int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry) -{ - int retry; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = length, - .buf = data, - } - }; - - for (retry = 0; retry < toRetry; retry++) { - if (i2c_transfer(client->adapter, msg, 1) == 1) - break; - msleep(20); - } - if (retry == toRetry) { - E("%s: i2c_read_block retry over %d\n", - __func__, toRetry); - return -EIO; - } - return 0; -} - -int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry) -{ - return i2c_himax_write(client, command, NULL, 0, toRetry); -} - -int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry) -{ - int retry/*, loop_i*/; - uint8_t buf[length]; - - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .len = length, - .buf = buf, - } - }; - - memcpy(buf, data, length); - - for (retry = 0; retry < toRetry; retry++) { - if (i2c_transfer(client->adapter, msg, 1) == 1) - break; - msleep(20); - } - - if (retry == toRetry) { - E("%s: i2c_write_block retry over %d\n", - __func__, toRetry); - return -EIO; - } - return 0; -} - -void himax_int_enable(int irqnum, int enable) -{ - if (enable == 1 && irq_enable_count == 0) { - enable_irq(irqnum); - irq_enable_count++; - } else if (enable == 0 && irq_enable_count == 1) { - disable_irq_nosync(irqnum); - irq_enable_count--; - } - I("irq_enable_count = %d", irq_enable_count); -} - -void himax_rst_gpio_set(int pinnum, uint8_t value) -{ - gpio_direction_output(pinnum, value); -} - -uint8_t himax_int_gpio_read(int pinnum) -{ - return gpio_get_value(pinnum); -} - -#if defined(CONFIG_HMX_DB) -static int himax_regulator_configure(struct i2c_client *client,struct himax_i2c_platform_data *pdata) -{ - int retval; - pdata->vcc_dig = regulator_get(&client->dev, - "vdd"); - if (IS_ERR(pdata->vcc_dig)) - { - E("%s: Failed to get regulator vdd\n", - __func__); - retval = PTR_ERR(pdata->vcc_dig); - return retval; - } - pdata->vcc_ana = regulator_get(&client->dev, - "avdd"); - if (IS_ERR(pdata->vcc_ana)) - { - E("%s: Failed to get regulator avdd\n", - __func__); - retval = PTR_ERR(pdata->vcc_ana); - regulator_put(pdata->vcc_ana); - return retval; - } - - return 0; -}; - -static int himax_power_on(struct himax_i2c_platform_data *pdata, bool on) -{ - int retval; - - if (on) - { - retval = regulator_enable(pdata->vcc_dig); - if (retval) - { - E("%s: Failed to enable regulator vdd\n", - __func__); - return retval; - } - msleep(100); - retval = regulator_enable(pdata->vcc_ana); - if (retval) - { - E("%s: Failed to enable regulator avdd\n", - __func__); - regulator_disable(pdata->vcc_dig); - return retval; - } - } - else - { - regulator_disable(pdata->vcc_dig); - regulator_disable(pdata->vcc_ana); - } - - return 0; -} - -int himax_ts_pinctrl_init(struct himax_ts_data *ts) -{ - int retval; - - /* Get pinctrl if target uses pinctrl */ - ts->ts_pinctrl = devm_pinctrl_get(&(ts->client->dev)); - if (IS_ERR_OR_NULL(ts->ts_pinctrl)) { - retval = PTR_ERR(ts->ts_pinctrl); - dev_dbg(&ts->client->dev, - "Target does not use pinctrl %d\n", retval); - goto err_pinctrl_get; - } - - ts->pinctrl_state_active - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_ACTIVE); - if (IS_ERR_OR_NULL(ts->pinctrl_state_active)) { - retval = PTR_ERR(ts->pinctrl_state_active); - dev_err(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_ACTIVE, retval); - goto err_pinctrl_lookup; - } - - ts->pinctrl_state_suspend - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_SUSPEND); - if (IS_ERR_OR_NULL(ts->pinctrl_state_suspend)) { - retval = PTR_ERR(ts->pinctrl_state_suspend); - dev_err(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_SUSPEND, retval); - goto err_pinctrl_lookup; - } - - ts->pinctrl_state_release - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_RELEASE); - if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { - retval = PTR_ERR(ts->pinctrl_state_release); - dev_dbg(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_RELEASE, retval); - } - - return 0; - -err_pinctrl_lookup: - devm_pinctrl_put(ts->ts_pinctrl); -err_pinctrl_get: - ts->ts_pinctrl = NULL; - return retval; -} - -int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) -{ - int error; - - error = himax_regulator_configure(client, pdata); - if (error) - { - E("Failed to intialize hardware\n"); - goto err_regulator_not_on; - } - -#ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - { - /* configure touchscreen reset out gpio */ - error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); - if (error) - { - E("unable to request gpio [%d]\n", - pdata->gpio_reset); - goto err_regulator_on; - } - - error = gpio_direction_output(pdata->gpio_reset, 0); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - goto err_gpio_reset_req; - } - } -#endif - - error = himax_power_on(pdata, true); - if (error) - { - E("Failed to power on hardware\n"); - goto err_gpio_reset_req; - } -#ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - { - /* configure touchscreen irq gpio */ - error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); - if (error) - { - E("unable to request gpio [%d]\n", - pdata->gpio_irq); - goto err_power_on; - } - error = gpio_direction_input(pdata->gpio_irq); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_irq); - goto err_gpio_irq_req; - } - client->irq = gpio_to_irq(pdata->gpio_irq); - } - else - { - E("irq gpio not provided\n"); - goto err_power_on; - } -#endif - - msleep(20); - -#ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - { - error = gpio_direction_output(pdata->gpio_reset, 1); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - goto err_gpio_irq_req; - } - } -#endif - return 0; -#ifdef HX_RST_PIN_FUNC - err_gpio_irq_req: -#endif -#ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - gpio_free(pdata->gpio_irq); - err_power_on: -#endif - himax_power_on(pdata, false); - err_gpio_reset_req: -#ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - gpio_free(pdata->gpio_reset); - err_regulator_on: -#endif - err_regulator_not_on: - - return error; -} - -#else -int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) -{ - int error=0; - -#ifdef HX_RST_PIN_FUNC - if (pdata->gpio_reset >= 0) - { - error = gpio_request(pdata->gpio_reset, "himax-reset"); - if (error < 0) - { - E("%s: request reset pin failed\n", __func__); - return error; - } - error = gpio_direction_output(pdata->gpio_reset, 0); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - return error; - } - } -#endif - if (pdata->gpio_3v3_en >= 0) - { - error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); - if (error < 0) - { - E("%s: request 3v3_en pin failed\n", __func__); - return error; - } - gpio_direction_output(pdata->gpio_3v3_en, 1); - I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en)); - } - -#ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - { - /* configure touchscreen irq gpio */ - error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); - if (error) - { - E("unable to request gpio [%d]\n",pdata->gpio_irq); - return error; - } - error = gpio_direction_input(pdata->gpio_irq); - if (error) - { - E("unable to set direction for gpio [%d]\n",pdata->gpio_irq); - return error; - } - client->irq = gpio_to_irq(pdata->gpio_irq); - } - else - { - E("irq gpio not provided\n"); - return error; - } -#endif - - msleep(20); - -#ifdef HX_RST_PIN_FUNC - if (pdata->gpio_reset >= 0) - { - error = gpio_direction_output(pdata->gpio_reset, 1); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - return error; - } - } - msleep(20); -#endif - - return error; - } -#endif - -static void himax_ts_isr_func(struct himax_ts_data *ts) -{ - himax_ts_work(ts); -} - -irqreturn_t himax_ts_thread(int irq, void *ptr) -{ - uint8_t diag_cmd; - struct himax_ts_data *ts = ptr; - struct timespec timeStart, timeEnd, timeDelta; - - diag_cmd = getDiagCommand(); - - if (ts->debug_log_level & BIT(2)) { - getnstimeofday(&timeStart); - usleep_range(5000, 7000); - //I(" Irq start time = %ld.%06ld s\n", - // timeStart.tv_sec, timeStart.tv_nsec/1000); - } - -#ifdef HX_SMART_WAKEUP - if (atomic_read(&ts->suspend_mode)&&(!FAKE_POWER_KEY_SEND)&&(ts->SMWP_enable)&&(!diag_cmd)) { - wake_lock_timeout(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); - msleep(200); - himax_wake_check_func(); - return IRQ_HANDLED; - } -#endif - himax_ts_isr_func((struct himax_ts_data *)ptr); - if(ts->debug_log_level & BIT(2)) { - getnstimeofday(&timeEnd); - timeDelta.tv_nsec = (timeEnd.tv_sec*1000000000+timeEnd.tv_nsec) - -(timeStart.tv_sec*1000000000+timeStart.tv_nsec); - //I("Irq finish time = %ld.%06ld s\n", - // timeEnd.tv_sec, timeEnd.tv_nsec/1000); - //I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000); - } - return IRQ_HANDLED; -} - -static void himax_ts_work_func(struct work_struct *work) -{ - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work); - himax_ts_work(ts); -} - -int tp_irq = -1; - -int himax_ts_register_interrupt(struct i2c_client *client) -{ - struct himax_ts_data *ts = i2c_get_clientdata(client); - int ret = 0; - - ts->irq_enabled = 0; - //Work functon - if (client->irq) {/*INT mode*/ - ts->use_irq = 1; - if(ic_data->HX_INT_IS_EDGE) - { - I("%s edge triiger falling\n ",__func__); - ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ts); - } - else - { - I("%s level trigger low\n ",__func__); - ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts); - } - if (ret == 0) { - ts->irq_enabled = 1; - irq_enable_count = 1; - tp_irq = client->irq; - I("%s: irq enabled at qpio: %d\n", __func__, client->irq); -#ifdef HX_SMART_WAKEUP - irq_set_irq_wake(client->irq, 1); -#endif - } else { - ts->use_irq = 0; - E("%s: request_irq failed\n", __func__); - } - } else { - I("%s: client->irq is empty, use polling mode.\n", __func__); - } - - if (!ts->use_irq) {/*if use polling mode need to disable HX_ESD_WORKAROUND function*/ - ts->himax_wq = create_singlethread_workqueue("himax_touch"); - - INIT_WORK(&ts->work, himax_ts_work_func); - - hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ts->timer.function = himax_ts_timer_func; - hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); - I("%s: polling mode enabled\n", __func__); - } - return ret; -} - -static int himax_common_suspend(struct device *dev) -{ - struct himax_ts_data *ts = dev_get_drvdata(dev); - - I("%s: enter \n", __func__); - - himax_chip_common_suspend(ts); - return 0; -} - -static int himax_common_resume(struct device *dev) -{ - struct himax_ts_data *ts = dev_get_drvdata(dev); - - I("%s: enter \n", __func__); - - himax_chip_common_resume(ts); - return 0; -} - -#if defined(CONFIG_FB) -int fb_notifier_callback(struct notifier_block *self, - unsigned long event, void *data) -{ - struct fb_event *evdata = data; - int *blank; - struct himax_ts_data *ts= - container_of(self, struct himax_ts_data, fb_notif); - - I(" %s\n", __func__); - if (evdata && evdata->data && event == FB_EVENT_BLANK && ts && - ts->client) { - blank = evdata->data; - - mutex_lock(&ts->fb_mutex); - switch (*blank) { - case FB_BLANK_UNBLANK: - if (!ts->probe_done) { - himax_ts_init(ts); - ts->probe_done = true; - } else { - himax_common_resume(&ts->client->dev); - } - break; - - case FB_BLANK_POWERDOWN: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_VSYNC_SUSPEND: - case FB_BLANK_NORMAL: - himax_common_suspend(&ts->client->dev); - break; - } - mutex_unlock(&ts->fb_mutex); - } - - return 0; -} -#endif - -static const struct i2c_device_id himax_common_ts_id[] = { - {HIMAX_common_NAME, 0 }, - {} -}; - -static const struct dev_pm_ops himax_common_pm_ops = { -#if (!defined(CONFIG_FB)) - .suspend = himax_common_suspend, - .resume = himax_common_resume, -#endif -}; - -#ifdef CONFIG_OF -static const struct of_device_id himax_match_table[] = { - {.compatible = "himax,hxcommon" }, - {}, -}; -#else -#define himax_match_table NULL -#endif - -static struct i2c_driver himax_common_driver = { - .id_table = himax_common_ts_id, - .probe = himax_chip_common_probe, - .remove = himax_chip_common_remove, - .driver = { - .name = HIMAX_common_NAME, - .owner = THIS_MODULE, - .of_match_table = himax_match_table, -#ifdef CONFIG_PM - .pm = &himax_common_pm_ops, -#endif - }, -}; - -static void __init himax_common_init_async(void *unused, async_cookie_t cookie) -{ - I("%s:Enter \n", __func__); - i2c_add_driver(&himax_common_driver); -} - -static int __init himax_common_init(void) -{ - I("Himax common touch panel driver init\n"); - async_schedule(himax_common_init_async, NULL); - return 0; -} - -static void __exit himax_common_exit(void) -{ - i2c_del_driver(&himax_common_driver); -} - -module_init(himax_common_init); -module_exit(himax_common_exit); - -MODULE_DESCRIPTION("Himax_common driver"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h deleted file mode 100644 index 1223685683aa..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_platform.h +++ /dev/null @@ -1,135 +0,0 @@ -/* Himax Android Driver Sample Code for Himax chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#ifndef HIMAX_PLATFORM_H -#define HIMAX_PLATFORM_H - -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_HMX_DB) -#include -#endif - -#define QCT - -#define HIMAX_I2C_RETRY_TIMES 10 - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) -#define D(x...) pr_debug("[HXTP] " x) -#define I(x...) pr_info("[HXTP] " x) -#define W(x...) pr_warning("[HXTP][WARNING] " x) -#define E(x...) pr_err("[HXTP][ERROR] " x) -#define DIF(x...) \ -do {\ - if (debug_flag) \ - pr_debug("[HXTP][DEBUG] " x) \ -} while(0) -#else -#define D(x...) -#define I(x...) -#define W(x...) -#define E(x...) -#define DIF(x...) -#endif - -#if defined(CONFIG_HMX_DB) -/* Analog voltage @2.7 V */ -#define HX_VTG_MIN_UV 2700000 -#define HX_VTG_MAX_UV 3300000 -#define HX_ACTIVE_LOAD_UA 15000 -#define HX_LPM_LOAD_UA 10 -/* Digital voltage @1.8 V */ -#define HX_VTG_DIG_MIN_UV 1800000 -#define HX_VTG_DIG_MAX_UV 1800000 -#define HX_ACTIVE_LOAD_DIG_UA 10000 -#define HX_LPM_LOAD_DIG_UA 10 - -#define HX_I2C_VTG_MIN_UV 1800000 -#define HX_I2C_VTG_MAX_UV 1800000 -#define HX_I2C_LOAD_UA 10000 -#define HX_I2C_LPM_LOAD_UA 10 -#endif - -#define HIMAX_common_NAME "himax_tp" -#define HIMAX_I2C_ADDR 0x48 -#define INPUT_DEV_NAME "himax-touchscreen" - -struct himax_i2c_platform_data { - int abs_x_min; - int abs_x_max; - int abs_x_fuzz; - int abs_y_min; - int abs_y_max; - int abs_y_fuzz; - int abs_pressure_min; - int abs_pressure_max; - int abs_pressure_fuzz; - int abs_width_min; - int abs_width_max; - int screenWidth; - int screenHeight; - uint8_t fw_version; - uint8_t tw_id; - uint8_t powerOff3V3; - uint8_t cable_config[2]; - uint8_t protocol_type; - int gpio_irq; - int gpio_reset; - int gpio_3v3_en; - int (*power)(int on); - void (*reset)(void); - struct himax_virtual_key *virtual_key; - struct kobject *vk_obj; - struct kobj_attribute *vk2Use; - - struct himax_config *hx_config; - int hx_config_size; -#if defined(CONFIG_HMX_DB) - bool i2c_pull_up; - bool digital_pwr_regulator; - int reset_gpio; - u32 reset_gpio_flags; - int irq_gpio; - u32 irq_gpio_flags; - - struct regulator *vcc_ana; //For Dragon Board - struct regulator *vcc_dig; //For Dragon Board - struct regulator *vcc_i2c; //For Dragon Board -#endif -}; - - -extern int irq_enable_count; -extern int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry); -extern int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry); -extern void himax_int_enable(int irqnum, int enable); -extern int himax_ts_register_interrupt(struct i2c_client *client); -extern void himax_rst_gpio_set(int pinnum, uint8_t value); -extern uint8_t himax_int_gpio_read(int pinnum); - -extern int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata); - -#if defined(CONFIG_FB) -extern int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); -#endif - -#endif From bb06c7ced3735fc0d38a78e201cbdc74dde680a7 Mon Sep 17 00:00:00 2001 From: Paul Chang Date: Tue, 10 Jul 2018 10:00:26 +0530 Subject: [PATCH 055/392] input: touchscreen: Add himax touchscreen support apq8053-lite FEP-V2 SOM has 2 variants of display Panel - 8" and 10". For 8" display panel the touch vendor is Himax. Add Himax touchscreen support for 8" Display Panel. Change-Id: I6d108f53e4b3b52b0a7cbf0de86f74f4f86f3366 Signed-off-by: Paul Chang Git-commit: aa2965fae3f8d791d0fd4c8105408bee807b540c Git-commit: 714259e2f1eadeb712fdb9cf6e6619fe6eece156 Git-commit: 788fbe836fcabb5493596a2ccc393645665e47c5 Git-commit: 884851757226bb87dd51c5686ee9935a7cd95403 Git-commit: a2b465b13af90f22233943c492b6f09a4fa892e7 Git-commit: 1f5b2aaafa1d9935b0831b641edebd18cf05eb04 Git-commit: 3f6ec12edd3200d6d3c4c32b93e4ed390160403d Git-commit: 7bc077d513ac739518734a4ab7fee80ca63a9d02 Git-commit: 97afcbfbca30b5eeb3b8acc10e2d1b430650e7a0 Git-commit: 566ec5a310816f2527a0f06e164a90fca7c04650 Git-commit: c91150831a152e1123902f36194802124b7d8aca Git-commit: c48e3f6d989efadc818563a154e8c029d6c8acfd Git-commit: fc785e480943fec46cc85a920592de714c9662e9 Git-commit: 2e38029b518618d33b295a9db251fdf183584de5 Git-commit: 6ae46c3501c85b874d0f430ead0ecd0b8a465af2 Git-commit: 2dbe6ff0b26c05930cfeb8079c98968d91f4ae85 Git-commit: 104a28fd7540c4674f8a02f4bad3f8a66b5d92d5 Git-commit: 262492fd69d729acdfef1a223e11155c9ed5301d Git-commit: 887a29104e1d895664642a27db7935c2bbc32d0f Git-commit: 0caefe38fb476103606494e13f830f2690acf430 Git-commit: f855d7e895df3d307ceee5cef69d410e816a4987 Git-Repo: https://github.com/HimaxSoftware/msm-3.18 Signed-off-by: Vijay Navnath Kamble --- .../input/touchscreen/himax_i2c_ts.txt | 57 + .../devicetree/bindings/vendor-prefixes.txt | 1 + drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/hxchipset/Kconfig | 46 + drivers/input/touchscreen/hxchipset/Makefile | 4 + .../touchscreen/hxchipset/himax_common.c | 1984 ++++++++++++++ .../touchscreen/hxchipset/himax_common.h | 472 ++++ .../input/touchscreen/hxchipset/himax_debug.c | 2205 +++++++++++++++ .../input/touchscreen/hxchipset/himax_debug.h | 197 ++ .../input/touchscreen/hxchipset/himax_ic.c | 2381 +++++++++++++++++ .../input/touchscreen/hxchipset/himax_ic.h | 148 + .../touchscreen/hxchipset/himax_platform.c | 783 ++++++ .../touchscreen/hxchipset/himax_platform.h | 157 ++ 14 files changed, 8448 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt create mode 100644 drivers/input/touchscreen/hxchipset/Kconfig create mode 100644 drivers/input/touchscreen/hxchipset/Makefile create mode 100644 drivers/input/touchscreen/hxchipset/himax_common.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_common.h create mode 100644 drivers/input/touchscreen/hxchipset/himax_debug.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_debug.h create mode 100644 drivers/input/touchscreen/hxchipset/himax_ic.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_ic.h create mode 100644 drivers/input/touchscreen/hxchipset/himax_platform.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_platform.h diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt new file mode 100644 index 000000000000..9889f55dd4bb --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt @@ -0,0 +1,57 @@ +Himax touch controller + +Required properties: + + - compatible : should be "himax,hxcommon" + - reg : i2c slave address of the device + - interrupt-parent : parent of interrupt + - interrupts : touch sample interrupt to indicate presense or release + of fingers on the panel. + - himax,irq-gpio : irq gpio + - himax,reset-gpio : reset gpio + +Optional property: + - vdd-supply : Analog power supply needed to power device + - vcc_i2c-supply : Power source required to pull up i2c bus + - himax,i2c-pull-up : specify to indicate pull up is needed + - himax,disable-gpios : specify to disable gpios in suspend (power saving) + - himax,button-map : virtual key code mappings to be used + - himax,x-flip : modify orientation of the x axis + - himax,y-flip : modify orientation of the y axis + - himax,panel-coords : touch panel min x, min y, max x and + max y resolution + - himax,display-coords : display min x, min y, max x and + max y resolution + - himax,reset-delay : reset delay for controller (ms), default 100 + - himax,fw-image-name : name of firmware .img file in /etc/firmware + - himax,power-down : fully power down regulators in suspend + - himax,do-lockdown : perform one time lockdown procedure + +Example: + i2c@f9927000 { /* BLSP1 QUP5 */ + cell-index = <5>; + compatible = "himax,hxcommon"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "qup_phys_addr"; + reg = <0xf9927000 0x1000>; + interrupt-names = "qup_err_intr"; + interrupts = <0 99 0>; + gpios = <&msmgpio 19 0>, /* SCL */ + <&msmgpio 18 0>; /* SDA */ + qcom,i2c-bus-freq = <100000>; + qcom,i2c-src-freq = <19200000>; + + himax_ts@20 { + compatible = "himax,hxcommon" + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <255 0x2008>; + vdd-supply = <&pm8994_l15>; + avdd-supply = <&pm8994_l22>; + himax,panel-coords = <0 720 0 1440>; + himax,display-coords = <0 720 0 1440>; + himax,irq-gpio = <&tlmm 255 0x2008>; + himax,rst-gpio = <&tlmm 8 0x00>; + }; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 9f22c1d8be95..5fc0fc631fd3 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -78,6 +78,7 @@ haoyu Haoyu Microelectronic Co. Ltd. hisilicon Hisilicon Limited. honeywell Honeywell hp Hewlett Packard +himax Himax Coroporation i2se I2SE GmbH ibm International Business Machines (IBM) idt Integrated Device Technologies, Inc. diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index dd9b928e3694..97fcd88d2d54 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1137,4 +1137,16 @@ config TOUCHSCREEN_MAXIM_STI source "drivers/input/touchscreen/gt9xx/Kconfig" +config TOUCHSCREEN_HIMAX_CHIPSET + bool "Himax touchpanel CHIPSET" + depends on I2C + help + Say Y here if you have a Himax CHIPSET touchscreen. + HIMAX controllers are multi touch controllers which can + report 10 touches at a time. + + If unsure, say N. + +source "drivers/input/touchscreen/hxchipset/Kconfig" + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index be0eb9b34f5b..499b8110fe6c 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -90,3 +90,4 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV) += synaptics_rmi_dev.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_fw_update.o obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/ +obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig new file mode 100644 index 000000000000..3dc5a026c851 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/Kconfig @@ -0,0 +1,46 @@ +# +# Himax Touchscreen driver configuration +# + +config TOUCHSCREEN_HIMAX_I2C + tristate "HIMAX chipset i2c touchscreen" + depends on TOUCHSCREEN_HIMAX_CHIPSET + help + Say Y here to enable support for HIMAX CHIPSET over I2C based touchscreens. + If unsure, say N. + + To compile this driver as a module, + This enables support for HIMAX CHIPSET over I2C based touchscreens. + +config TOUCHSCREEN_HIMAX_DEBUG + tristate "HIMAX debug function" + depends on TOUCHSCREEN_HIMAX_I2C + help + Say Y here to enable support for HIMAX debug function. + + If unsure, say N. + + To compile this driver as a module, + This enables support for HIMAX debug function. + +config TOUCHSCREEN_HIMAX_ITO_TEST + tristate "HIMAX driver test over Dragon Board" + depends on TOUCHSCREEN_HIMAX_I2C + help + Say Y here to enable support for HIMAX driver test over Dragon Board. + + If unsure, say N. + + To compile this driver as a module, + this enables support for HIMAX driver test over Dragon Board. + +config HMX_DB + tristate "HIMAX driver test over Dragon Board" + depends on TOUCHSCREEN_HIMAX_I2C + help + Say Y here to enable support for HIMAX driver test over Dragon Board. + + If unsure, say N. + + To compile this driver as a module, + this enables support for HIMAX driver test over Dragon Board. diff --git a/drivers/input/touchscreen/hxchipset/Makefile b/drivers/input/touchscreen/hxchipset/Makefile new file mode 100644 index 000000000000..522907a48956 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/Makefile @@ -0,0 +1,4 @@ +# Makefile for the Himax touchscreen drivers. + +obj-$(CONFIG_TOUCHSCREEN_HIMAX_I2C) += himax_platform.o himax_ic.o himax_common.o himax_debug.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX_ITO_TEST) += himax_ito_test.o \ No newline at end of file diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c new file mode 100644 index 000000000000..d4bc5beb0203 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -0,0 +1,1984 @@ + /* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_common.h" +#include "himax_ic.h" + +#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F +#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) +#define FRAME_COUNT 5 + +#if defined(HX_AUTO_UPDATE_FW) + char *i_CTPM_firmware_name = "HX83100_Amber_0B01_030E.bin"; + const struct firmware *i_CTPM_FW = NULL; +#endif + +/*static int tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; +// for Virtual key array */ + +struct himax_ts_data *private_ts; +struct himax_ic_data *ic_data; + +static int HX_TOUCH_INFO_POINT_CNT; + +static uint8_t vk_press = 0x00; +static uint8_t AA_press = 0x00; +static uint8_t EN_NoiseFilter = 0x00; +static int hx_point_num; /*for himax_ts_work_func use*/ +static int p_point_num = 0xFFFF; +static int tpd_key = 0x00; +static int tpd_key_old = 0x00; +static int probe_fail_flag; +static bool config_load; +static struct himax_config *config_selected; + +/*static int iref_number = 11;*/ +/*static bool iref_found = false;*/ + + +#if defined(CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void himax_ts_early_suspend(struct early_suspend *h); +static void himax_ts_late_resume(struct early_suspend *h); +#endif + +int himax_input_register(struct himax_ts_data *ts) +{ + int ret; + + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) { + ret = -ENOMEM; + E("%s: Failed to allocate input device\n", __func__); + return ret; + } + ts->input_dev->name = "himax-touchscreen"; + + set_bit(EV_SYN, ts->input_dev->evbit); + set_bit(EV_ABS, ts->input_dev->evbit); + set_bit(EV_KEY, ts->input_dev->evbit); + + set_bit(KEY_BACK, ts->input_dev->keybit); + set_bit(KEY_HOME, ts->input_dev->keybit); + set_bit(KEY_MENU, ts->input_dev->keybit); + set_bit(KEY_SEARCH, ts->input_dev->keybit); +#if defined(HX_SMART_WAKEUP) + set_bit(KEY_POWER, ts->input_dev->keybit); + set_bit(KEY_CUST_01, ts->input_dev->keybit); + set_bit(KEY_CUST_02, ts->input_dev->keybit); + set_bit(KEY_CUST_03, ts->input_dev->keybit); + set_bit(KEY_CUST_04, ts->input_dev->keybit); + set_bit(KEY_CUST_05, ts->input_dev->keybit); + set_bit(KEY_CUST_06, ts->input_dev->keybit); + set_bit(KEY_CUST_07, ts->input_dev->keybit); + set_bit(KEY_CUST_08, ts->input_dev->keybit); + set_bit(KEY_CUST_09, ts->input_dev->keybit); + set_bit(KEY_CUST_10, ts->input_dev->keybit); + set_bit(KEY_CUST_11, ts->input_dev->keybit); + set_bit(KEY_CUST_12, ts->input_dev->keybit); + set_bit(KEY_CUST_13, ts->input_dev->keybit); + set_bit(KEY_CUST_14, ts->input_dev->keybit); + set_bit(KEY_CUST_15, ts->input_dev->keybit); +#endif + set_bit(BTN_TOUCH, ts->input_dev->keybit); + + set_bit(KEY_F10, ts->input_dev->keybit); + + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + + if (ts->protocol_type == PROTOCOL_TYPE_A) { + /*ts->input_dev->mtsize = ts->nFinger_support;*/ + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, + 0, 3, 0, 0); + } else {/* PROTOCOL_TYPE_B */ + set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); + input_mt_init_slots(ts->input_dev, ts->nFinger_support, 0); + } + + I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max, + ts->pdata->abs_y_min, ts->pdata->abs_y_max); + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, + ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, + ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, + ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, + ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, + ts->pdata->abs_width_min, ts->pdata->abs_width_max, + ts->pdata->abs_pressure_fuzz, 0); + +/*input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, +((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0);*/ +/*input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, +(BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0);*/ + + return input_register_device(ts->input_dev); +} + +static void calcDataSize(uint8_t finger_num) +{ + struct himax_ts_data *ts_data = private_ts; + + ts_data->coord_data_size = 4 * finger_num; + ts_data->area_data_size = ((finger_num / 4) + + (finger_num % 4 ? 1 : 0)) * 4; + ts_data->raw_data_frame_size = 128 - + ts_data->coord_data_size - + ts_data->area_data_size - 4 - 4 - 1; + + ts_data->raw_data_nframes = + ((uint32_t)ts_data->x_channel * + ts_data->y_channel + ts_data->x_channel + ts_data->y_channel) / + ts_data->raw_data_frame_size + (((uint32_t)ts_data->x_channel * + ts_data->y_channel + ts_data->x_channel + ts_data->y_channel) % + ts_data->raw_data_frame_size) ? 1 : 0; + + I("%s: coord_data_size: %d, area_data_size:%d", + __func__, ts_data->coord_data_size, ts_data->area_data_size); + I("raw_data_frame_size:%d, raw_data_nframes:%d", + ts_data->raw_data_frame_size, ts_data->raw_data_nframes); +} + +static void calculate_point_number(void) +{ + HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4; + + if ((ic_data->HX_MAX_PT % 4) == 0) + HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4; + else + HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) + 1) * 4; +} + +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static int himax_read_Sensor_ID(struct i2c_client *client) +{ + uint8_t val_high[1], val_low[1], ID0 = 0, ID1 = 0; + char data[3]; + const int normalRetry = 10; + int sensor_id; + + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x02;/*ID pin PULL High*/ + i2c_himax_master_write(client, &data[0], 3, normalRetry); + usleep(1000); + + /*read id pin high*/ + i2c_himax_read(client, 0x57, val_high, 1, normalRetry); + + data[0] = 0x56; data[1] = 0x01; + data[2] = 0x01;/*ID pin PULL Low*/ + i2c_himax_master_write(client, &data[0], 3, normalRetry); + usleep(1000); + + /*read id pin low*/ + i2c_himax_read(client, 0x57, val_low, 1, normalRetry); + + if ((val_high[0] & 0x01) == 0) + ID0 = 0x02;/*GND*/ + else if ((val_low[0] & 0x01) == 0) + ID0 = 0x01;/*Floating*/ + else + ID0 = 0x04;/*VCC*/ + + if ((val_high[0] & 0x02) == 0) + ID1 = 0x02;/*GND*/ + else if ((val_low[0] & 0x02) == 0) + ID1 = 0x01;/*Floating*/ + else + ID1 = 0x04;/*VCC*/ + if ((ID0 == 0x04) && (ID1 != 0x04)) { + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x01;/*ID pin PULL High,Low*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); + + } else if ((ID0 != 0x04) && (ID1 == 0x04)) { + data[0] = 0x56; data[1] = 0x01; + data[2] = 0x02;/*ID pin PULL Low,High*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); + + } else if ((ID0 == 0x04) && (ID1 == 0x04)) { + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x02;/*ID pin PULL High,High*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); + + } + sensor_id = (ID1<<4)|ID0; + + data[0] = 0xE4; data[1] = sensor_id; + i2c_himax_master_write(client, + &data[0], 2, normalRetry);/*Write to MCU*/ + usleep(1000); + + return sensor_id; + +} +#endif +static void himax_power_on_initCMD(struct i2c_client *client) +{ + I("%s:\n", __func__); + himax_touch_information(client); + /*himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM */ +} + +#ifdef HX_AUTO_UPDATE_FW +static int i_update_FW(void) +{ + int upgrade_times = 0; + int fullFileLength = 0; + int i_FW_VER = 0, i_CFG_VER = 0; + int ret = -1, result = 0; + /*uint8_t tmp_addr[4];*/ + /*uint8_t tmp_data[4];*/ + int CRC_from_FW = 0; + int CRC_Check_result = 0; + + ret = himax_load_CRC_bin_file(private_ts->client); + if (ret < 0) { + E("%s: himax_load_CRC_bin_file fail Error Code=%d.\n", + __func__, ret); + ret = -1; + return ret; + } + I("file name = %s\n", i_CTPM_firmware_name); + ret = request_firmware(&i_CTPM_FW, + i_CTPM_firmware_name, private_ts->dev); + if (ret < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, ret); + ret = -2; + return ret; + } + + if (i_CTPM_FW == NULL) { + I("%s: i_CTPM_FW = NULL\n", __func__); + ret = -3; + return ret; + } + fullFileLength = i_CTPM_FW->size; + + i_FW_VER = i_CTPM_FW->data[FW_VER_MAJ_FLASH_ADDR]<<8 + | i_CTPM_FW->data[FW_VER_MIN_FLASH_ADDR]; + i_CFG_VER = i_CTPM_FW->data[CFG_VER_MAJ_FLASH_ADDR]<<8 + | i_CTPM_FW->data[CFG_VER_MIN_FLASH_ADDR]; + + I("%s: i_fullFileLength = %d\n", __func__, fullFileLength); + + himax_sense_off(private_ts->client); + msleep(500); + + CRC_from_FW = himax_check_CRC(private_ts->client, fw_image_64k); + CRC_Check_result = + Calculate_CRC_with_AP((unsigned char *)i_CTPM_FW->data, + CRC_from_FW, fw_image_64k); + I("%s: Check sum result = %d\n", __func__, CRC_Check_result); + /*I("%s: ic_data->vendor_fw_ver = %X, i_FW_VER = %X,\n", + __func__, ic_data->vendor_fw_ver, i_FW_VER);*/ + /*I("%s: ic_data->vendor_config_ver = %X, i_CFG_VER = %X,\n", + __func__, ic_data->vendor_config_ver, i_CFG_VER);*/ + + if ((CRC_Check_result == 0) || + (ic_data->vendor_fw_ver < i_FW_VER) || + (ic_data->vendor_config_ver < i_CFG_VER)) { + himax_int_enable(private_ts->client->irq, 0); +update_retry: + if (fullFileLength == FW_SIZE_60k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_60k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_64k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_64k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_124k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_124k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_128k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_128k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } + if (ret == 0) { + upgrade_times++; + E("%s: TP upgrade error, upgrade_times = %d\n", + __func__, upgrade_times); + if (upgrade_times < 3) + goto update_retry; + else { + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + result = -1;/*upgrade fail*/ + } + } else if (ret == 1) { + /* + // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + + // 2. Write driver initial code condition + //write value from AHB I2C:0x8001_C603 = 0x000000FF + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xC6; tmp_addr[0] = 0x03; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xFF; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + + // 1. Set DDREG_Req = 0(0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + */ + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + + ic_data->vendor_fw_ver = i_FW_VER; + ic_data->vendor_config_ver = i_CFG_VER; + result = 1;/*upgrade success*/ + I("%s: TP upgrade OK\n", __func__); + } + + himax_int_enable(private_ts->client->irq, 1); + return result; + + } else { + himax_sense_on(private_ts->client, 0x01); + return 0;/*NO upgrade*/ + } +} +#endif + +#ifdef HX_RST_PIN_FUNC +void himax_HW_reset(uint8_t loadconfig, uint8_t int_off) +{ + struct himax_ts_data *ts = private_ts; + int ret = 0; + + return; + if (ts->rst_gpio) { + if (int_off) { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq, 0); + else { + hrtimer_cancel(&ts->timer); + ret = cancel_work_sync(&ts->work); + } + } + + I("%s: Now reset the Touch chip.\n", __func__); + + himax_rst_gpio_set(ts->rst_gpio, 0); + msleep(20); + himax_rst_gpio_set(ts->rst_gpio, 1); + msleep(20); + + if (loadconfig) + himax_loadSensorConfig(private_ts->client, + private_ts->pdata); + + if (int_off) { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq, 1); + else + hrtimer_start(&ts->timer, + ktime_set(1, 0), HRTIMER_MODE_REL); + } + } +} +#endif + +int himax_loadSensorConfig(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) +{ + int err = -1; + + if (!client) { + E("%s: Necessary parameters client are null!\n", __func__); + return err; + } + if (config_load == false) { + config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); + if (config_selected == NULL) { + E("%s: alloc config_selected fail!\n", __func__); + return err; + } + } + himax_power_on_initCMD(client); + + himax_int_enable(client->irq, 0); + himax_read_FW_ver(client); +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true, false); +#endif + himax_int_enable(client->irq, 1); + I("FW_VER : %X\n", ic_data->vendor_fw_ver); + + ic_data->vendor_sensor_id = 0x2602; + I("sensor_id=%x.\n", ic_data->vendor_sensor_id); + + himax_sense_on(private_ts->client, 0x01);/*1=Flash, 0=SRAM*/ + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + I("%s: initialization complete\n", __func__); + + return 1; +} + +#ifdef HX_ESD_WORKAROUND +void ESD_HW_REST(void) +{ + I("START_Himax TP: ESD - Reset\n"); + + HX_report_ESD_event(); + ESD_00_counter = 0; + ESD_00_Flag = 0; + /*************************************/ + if (private_ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(private_ts->input_dev); + input_report_key(private_ts->input_dev, BTN_TOUCH, 0); + input_sync(private_ts->input_dev); + /*************************************/ + + I("END_Himax TP: ESD - Reset\n"); +} +#endif +#ifdef HX_HIGH_SENSE +void himax_set_HSEN_func(struct i2c_client *client, uint8_t HSEN_enable) +{ + uint8_t tmp_data[4]; + + if (HSEN_enable) { + I(" %s in", __func__); +HSEN_bit_retry: + himax_set_HSEN_enable(client, HSEN_enable); + msleep(20); + himax_get_HSEN_enable(client, tmp_data); + I("%s: Read HSEN bit data[0]=%x data[1]=%x", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); + + if (tmp_data[0] != 0x01) { + I("%s: retry HSEN bit write data[0]=%x\n", + __func__, tmp_data[0]); + goto HSEN_bit_retry; + } + } +} + +static void himax_HSEN_func(struct work_struct *work) +{ + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, hsen_work.work); + + himax_set_HSEN_func(ts->client, ts->HSEN_enable); +} + +#endif + +#ifdef HX_SMART_WAKEUP +#ifdef HX_GESTURE_TRACK +static void gest_pt_log_coordinate(int rx, int tx) +{ + /*driver report x y with range 0 - 255*/ + /* And we scale it up to x/y coordinates*/ + gest_pt_x[gest_pt_cnt] = rx * (ic_data->HX_X_RES) / 255; + gest_pt_y[gest_pt_cnt] = tx * (ic_data->HX_Y_RES) / 255; +} +#endif +static int himax_parse_wake_event(struct himax_ts_data *ts) +{ + uint8_t buf[64]; + unsigned char check_sum_cal = 0; +#ifdef HX_GESTURE_TRACK + int tmp_max_x = 0x00, tmp_min_x = 0xFFFF, + tmp_max_y = 0x00, tmp_min_y = 0xFFFF; + int gest_len; +#endif + int i = 0, check_FC = 0, gesture_flag = 0; + + himax_burst_enable(ts->client, 0); + himax_read_event_stack(ts->client, buf, 56); + + for (i = 0 ; i < GEST_PTLG_ID_LEN ; i++) { + if (check_FC == 0) { + if ((buf[0] != 0x00) && + ((buf[0] <= 0x0F) || (buf[0] == 0x80))) { + check_FC = 1; + gesture_flag = buf[i]; + } else { + check_FC = 0; + I("ID START at %x,value = %x skip event\n", + i, buf[i]); + break; + } + } else { + if (buf[i] != gesture_flag) { + check_FC = 0; + I("ID NOT same %x != %x So STOP parse event\n", + buf[i], gesture_flag); + break; + } + } + + I("0x%2.2X ", buf[i]); + if (i % 8 == 7) + I("\n"); + } + I("Himax gesture_flag= %x\n", gesture_flag); + I("Himax check_FC is %d\n", check_FC); + + if (check_FC == 0) + return 0; + if (buf[GEST_PTLG_ID_LEN] != GEST_PTLG_HDR_ID1 + || buf[GEST_PTLG_ID_LEN+1] != GEST_PTLG_HDR_ID2) + return 0; + for (i = 0 ; i < (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN) ; i++) { + I("P[%x]=0x%2.2X\n", i, buf[i]); + I("checksum=0x%2.2X\n", check_sum_cal); + check_sum_cal += buf[i]; + } + if ((check_sum_cal != 0x00)) { + I(" %s : check_sum_cal: 0x%02X\n", __func__ , check_sum_cal); + return 0; + } +#ifdef HX_GESTURE_TRACK + if (buf[GEST_PTLG_ID_LEN] == GEST_PTLG_HDR_ID1 + && buf[GEST_PTLG_ID_LEN+1] == GEST_PTLG_HDR_ID2) { + gest_len = buf[GEST_PTLG_ID_LEN + 2]; + I("gest_len = %d ", gest_len); + i = 0; + gest_pt_cnt = 0; + I("gest doornidate start\n %s", __func__); + while (i < (gest_len + 1) / 2) { + gest_pt_log_coordinate + (buf[GEST_PTLG_ID_LEN + 4 + i * 2], + buf[GEST_PTLG_ID_LEN + 4 + i * 2 + 1]); + i++; + + I("gest_pt_x[%d]=%d\n", + gest_pt_cnt, gest_pt_x[gest_pt_cnt]); + I("gest_pt_y[%d]=%d\n", + gest_pt_cnt, gest_pt_y[gest_pt_cnt]); + + gest_pt_cnt += 1; + } + if (gest_pt_cnt) { + for (i = 0 ; i < gest_pt_cnt ; i++) { + if (tmp_max_x < gest_pt_x[i]) + tmp_max_x = gest_pt_x[i]; + if (tmp_min_x > gest_pt_x[i]) + tmp_min_x = gest_pt_x[i]; + if (tmp_max_y < gest_pt_y[i]) + tmp_max_y = gest_pt_y[i]; + if (tmp_min_y > gest_pt_y[i]) + tmp_min_y = gest_pt_y[i]; + } + I("gest_point x_min= %d, x_max= %d\n", + tmp_min_x, tmp_max_x); + I("y_min= %d, y_max= %d\n", + tmp_min_y, tmp_max_y); + gest_start_x = gest_pt_x[0]; + gn_gesture_coor[0] = gest_start_x; + gest_start_y = gest_pt_y[0]; + gn_gesture_coor[1] = gest_start_y; + gest_end_x = gest_pt_x[gest_pt_cnt - 1]; + gn_gesture_coor[2] = gest_end_x; + gest_end_y = gest_pt_y[gest_pt_cnt - 1]; + gn_gesture_coor[3] = gest_end_y; + gest_width = tmp_max_x - tmp_min_x; + gn_gesture_coor[4] = gest_width; + gest_height = tmp_max_y - tmp_min_y; + gn_gesture_coor[5] = gest_height; + gest_mid_x = (tmp_max_x + tmp_min_x) / 2; + gn_gesture_coor[6] = gest_mid_x; + gest_mid_y = (tmp_max_y + tmp_min_y) / 2; + gn_gesture_coor[7] = gest_mid_y; + /*gest_up_x*/ + gn_gesture_coor[8] = gest_mid_x; + /*gest_up_y*/ + gn_gesture_coor[9] = gest_mid_y - gest_height / 2; + /*gest_down_x*/ + gn_gesture_coor[10] = gest_mid_x; + /*gest_down_y*/ + gn_gesture_coor[11] = gest_mid_y + gest_height / 2; + /*gest_left_x*/ + gn_gesture_coor[12] = gest_mid_x - gest_width / 2; + /*gest_left_y*/ + gn_gesture_coor[13] = gest_mid_y; + /*gest_right_x*/ + gn_gesture_coor[14] = gest_mid_x + gest_width / 2; + /*gest_right_y*/ + gn_gesture_coor[15] = gest_mid_y; + + } + + } +#endif + if (gesture_flag != 0x80) { + if (!ts->gesture_cust_en[gesture_flag]) { + I("%s NOT report customer key\n ", __func__); + return 0;/*NOT report customer key*/ + } + } else { + if (!ts->gesture_cust_en[0]) { + I("%s NOT report report double click\n", __func__); + return 0;/*NOT report power key*/ + } + } + + if (gesture_flag == 0x80) + return EV_GESTURE_PWR; + else + return gesture_flag; +} + +void himax_wake_check_func(void) +{ + int ret_event = 0, KEY_EVENT = 0; + + ret_event = himax_parse_wake_event(private_ts); + switch (ret_event) { + case EV_GESTURE_PWR: + KEY_EVENT = KEY_POWER; + break; + case EV_GESTURE_01: + KEY_EVENT = KEY_CUST_01; + break; + case EV_GESTURE_02: + KEY_EVENT = KEY_CUST_02; + break; + case EV_GESTURE_03: + KEY_EVENT = KEY_CUST_03; + break; + case EV_GESTURE_04: + KEY_EVENT = KEY_CUST_04; + break; + case EV_GESTURE_05: + KEY_EVENT = KEY_CUST_05; + break; + case EV_GESTURE_06: + KEY_EVENT = KEY_CUST_06; + break; + case EV_GESTURE_07: + KEY_EVENT = KEY_CUST_07; + break; + case EV_GESTURE_08: + KEY_EVENT = KEY_CUST_08; + break; + case EV_GESTURE_09: + KEY_EVENT = KEY_CUST_09; + break; + case EV_GESTURE_10: + KEY_EVENT = KEY_CUST_10; + break; + case EV_GESTURE_11: + KEY_EVENT = KEY_CUST_11; + break; + case EV_GESTURE_12: + KEY_EVENT = KEY_CUST_12; + break; + case EV_GESTURE_13: + KEY_EVENT = KEY_CUST_13; + break; + case EV_GESTURE_14: + KEY_EVENT = KEY_CUST_14; + break; + case EV_GESTURE_15: + KEY_EVENT = KEY_CUST_15; + break; + } + if (ret_event) { + I(" %s SMART WAKEUP KEY event %x press\n", + __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 1); + input_sync(private_ts->input_dev); + /*msleep(100);*/ + I(" %s SMART WAKEUP KEY event %x release\n", + __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 0); + input_sync(private_ts->input_dev); + FAKE_POWER_KEY_SEND = true; +#ifdef HX_GESTURE_TRACK + I("gest_start_x= %d, gest_start_y= %d\n", + gest_start_x, gest_start_y); + I("gest_end_x= %d, gest_end_y= %d\n", + gest_end_x, gest_end_y); + I("gest_width= %d, gest_height= %d\n", + gest_width, gest_height); + I("gest_mid_x= %d, gest_mid_y= %d\n", + gest_mid_x, gest_mid_y); + I("gest_up_x= %d, gest_up_y= %d\n", + gn_gesture_coor[8], gn_gesture_coor[9]); + I("gest_down_x= %d, gest_down_y= %d\n", + gn_gesture_coor[10], gn_gesture_coor[11]); + I("gest_left_x= %d, gest_left_y= %d\n", + gn_gesture_coor[12], gn_gesture_coor[13]); + I("gest_right_x= %d, gest_right_y= %d\n", + gn_gesture_coor[14], gn_gesture_coor[15]); +#endif + } +} + +#endif +static void himax_ts_button_func(int tp_key_index, struct himax_ts_data *ts) +{ + uint16_t x_position = 0, y_position = 0; + + if (tp_key_index != 0x00) { + I("virtual key index =%x\n", tp_key_index); + if (tp_key_index == 0x01) { + vk_press = 1; + I("back key pressed\n"); + if (ts->pdata->virtual_key) { + if (ts->button[0].index) { + x_position = (ts->button[0].x_range_min + + ts->button[0].x_range_max) / 2; + y_position = (ts->button[0].y_range_min + + ts->button[0].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type + == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_BACK, 1); + } else if (tp_key_index == 0x02) { + vk_press = 1; + I("home key pressed\n"); + if (ts->pdata->virtual_key) { + if (ts->button[1].index) { + x_position = (ts->button[1].x_range_min + + ts->button[1].x_range_max) / 2; + y_position = (ts->button[1].y_range_min + + ts->button[1].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type + == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_HOME, 1); + } else if (tp_key_index == 0x04) { + vk_press = 1; + I("APP_switch key pressed\n"); + if (ts->pdata->virtual_key) { + if (ts->button[2].index) { + x_position = (ts->button[2].x_range_min + + ts->button[2].x_range_max) / 2; + y_position = (ts->button[2].y_range_min + + ts->button[2].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == + PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_F10, 1); + } + input_sync(ts->input_dev); + } else {/*tp_key_index =0x00*/ + I("virtual key released\n"); + vk_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, 0); + } + input_report_key(ts->input_dev, KEY_BACK, 0); + input_report_key(ts->input_dev, KEY_HOME, 0); + input_report_key(ts->input_dev, KEY_F10, 0); + input_sync(ts->input_dev); + } +} + +void himax_ts_work(struct himax_ts_data *ts) +{ + int ret = 0; + uint8_t finger_num, hw_reset_check[2]; + uint8_t buf[128]; + uint8_t finger_on = 0; + int32_t loop_i; + uint16_t check_sum_cal = 0; + int raw_cnt_max; + int raw_cnt_rmd; + int hx_touch_info_size; + uint8_t coordInfoSize = ts->coord_data_size + ts->area_data_size + 4; + +#ifdef HX_TP_PROC_DIAG + int16_t *mutual_data; + int16_t *self_data; + uint8_t diag_cmd; + int i; + int mul_num; + int self_num; + int RawDataLen = 0; + /*coordinate dump start*/ + char coordinate_char[15 + (ic_data->HX_MAX_PT + 5) * 2 * 5 + 2]; + struct timeval t; + struct tm broken; + /*coordinate dump end*/ +#endif + + memset(buf, 0x00, sizeof(buf)); + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); + + raw_cnt_max = ic_data->HX_MAX_PT / 4; + raw_cnt_rmd = ic_data->HX_MAX_PT % 4; +#if defined(HX_USB_DETECT2) + himax_cable_detect_func(); +#endif + + if (raw_cnt_rmd != 0x00) { /*more than 4 fingers*/ + RawDataLen = cal_data_len(raw_cnt_rmd, + ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT + raw_cnt_max + 2) * 4; + } else { /*less than 4 fingers*/ + RawDataLen = cal_data_len(raw_cnt_rmd, + ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT + raw_cnt_max + 1) * 4; + } + +#ifdef HX_TP_PROC_DIAG + diag_cmd = getDiagCommand(); + if (diag_cmd) { + ret = read_event_stack(ts->client, buf, 128); + } else { + if (touch_monitor_stop_flag != 0) { + ret = read_event_stack(ts->client, buf, 128); + touch_monitor_stop_flag--; + } else { + ret = read_event_stack(ts->client, + buf, hx_touch_info_size); + } + } + + if (!ret) +#else + if (!read_event_stack(ts->client, buf, hx_touch_info_size)) +#endif + { + E("%s: can't read data from chip!\n", __func__); + goto err_workqueue_out; + } + post_read_event_stack(ts->client); +#ifdef HX_ESD_WORKAROUND + for (i = 0; i < hx_touch_info_size; i++) { + if (buf[i] == 0xED) { /*case 1 ESD recovery flow*/ + check_sum_cal = 1; + + } else if (buf[i] == 0x00) { + ESD_00_Flag = 1; + } else { + check_sum_cal = 0; + ESD_00_counter = 0; + ESD_00_Flag = 0; + i = hx_touch_info_size; + break; + } + } + if (ESD_00_Flag == 1) + ESD_00_counter++; + if (ESD_00_counter > 1) + check_sum_cal = 2; + if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0) { + I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); + ESD_HW_REST(); + return; + } + if (check_sum_cal == 1 && HX_ESD_RESET_ACTIVATE == 0) { + I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n"); + ESD_HW_REST(); + return; + } else if (HX_ESD_RESET_ACTIVATE) { +#ifdef HX_SMART_WAKEUP + queue_delayed_work(ts->himax_smwp_wq, + &ts->smwp_work, msecs_to_jiffies(50)); +#endif +#ifdef HX_HIGH_SENSE + queue_delayed_work(ts->himax_hsen_wq, + &ts->hsen_work, msecs_to_jiffies(50)); +#endif +/*drop 1st interrupts after chip reset*/ + HX_ESD_RESET_ACTIVATE = 0; + I("[HIMAX TP MSG]:%s: Back from reset,ready to serve.\n", + __func__); + } +#endif + for (loop_i = 0, check_sum_cal = 0; + loop_i < hx_touch_info_size; loop_i++) + check_sum_cal += buf[loop_i]; + + if ((check_sum_cal % 0x100 != 0)) { + I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", + check_sum_cal); + return; + } + if (ts->debug_log_level & BIT(0)) { + I("%s: raw data:\n", __func__); + for (loop_i = 0; loop_i < hx_touch_info_size; loop_i++) { + I("P %d = 0x%2.2X ", loop_i, buf[loop_i]); + if (loop_i % 8 == 7) + I("\n"); + } + } + + /*touch monitor raw data fetch*/ +#ifdef HX_TP_PROC_DIAG + diag_cmd = getDiagCommand(); + if (diag_cmd >= 1 && diag_cmd <= 6) { + /*Check 124th byte CRC*/ + if (!diag_check_sum(hx_touch_info_size, buf)) + goto bypass_checksum_failed_packet; + +#ifdef HX_TP_PROC_2T2R + if (Is_2T2R && diag_cmd == 4) { + mutual_data = getMutualBuffer_2(); + self_data = getSelfBuffer(); + + /* initiallize the block number of mutual and self*/ + mul_num = getXChannel_2() * getYChannel_2(); + +#ifdef HX_EN_SEL_BUTTON + self_num = getXChannel_2() + + getYChannel_2() + ic_data->HX_BT_NUM; +#else + self_num = getXChannel_2() + getYChannel_2(); +#endif + } else +#endif + { + mutual_data = getMutualBuffer(); + self_data = getSelfBuffer(); + + /* initiallize the block number of mutual and self*/ + mul_num = getXChannel() * getYChannel(); + +#ifdef HX_EN_SEL_BUTTON + self_num = getXChannel() + + getYChannel() + ic_data->HX_BT_NUM; +#else + self_num = getXChannel() + getYChannel(); +#endif + } + + diag_parse_raw_data(hx_touch_info_size, + RawDataLen, mul_num, self_num, buf, + diag_cmd, mutual_data, self_data); + + } else if (diag_cmd == 7) { + memcpy(&(diag_coor[0]), &buf[0], 128); + } + /*coordinate dump start*/ + if (coordinate_dump_enable == 1) { + for (i = 0; i < (15 + (ic_data-> + HX_MAX_PT + 5) * 2 * 5); + i++) { + coordinate_char[i] = 0x20; + } + coordinate_char[15 + + (ic_data->HX_MAX_PT + 5) * 2 * 5] = 0xD; + coordinate_char[15 + + (ic_data->HX_MAX_PT + 5) * 2 * 5 + 1] = 0xA; + } + /*coordinate dump end*/ +bypass_checksum_failed_packet: +#endif + EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 3); + /*I("EN_NoiseFilter=%d\n",EN_NoiseFilter);*/ + EN_NoiseFilter = EN_NoiseFilter & 0x01; + /*I("EN_NoiseFilter2=%d\n",EN_NoiseFilter);*/ + +#if defined(HX_EN_SEL_BUTTON) || defined(HX_EN_MUT_BUTTON) + tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 4); + if (tpd_key == 0x0F) {/*All (VK+AA)leave*/ + tpd_key = 0x00; + } + /*I("[DEBUG] tpd_key: %x\r\n", tpd_key);*/ +#else + tpd_key = 0x00; +#endif + + p_point_num = hx_point_num; + + if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) + hx_point_num = 0; + else + hx_point_num = buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; + + /* Touch Point information*/ + if ((hx_point_num != 0) && (vk_press == 0x00)) { + uint16_t old_finger = ts->pre_finger_mask; + + ts->pre_finger_mask = 0; + finger_num = buf[coordInfoSize - 4] & 0x0F; + finger_on = 1; + AA_press = 1; + for (i = 0; i < ts->nFinger_support; i++) { + int base = i * 4; + int x = buf[base] << 8 | buf[base + 1]; + int y = (buf[base + 2] << 8 | buf[base + 3]); + int w = buf[(ts->nFinger_support * 4) + i]; + + if (x >= 0 && x <= ts->pdata->abs_x_max + && y >= 0 && y <= ts->pdata->abs_y_max) { + finger_num--; + if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 0)) + && (ts->useScreenRes)) { + I("status:Screen:F:%02d", i + 1); + I("Down,X:%d,Y:%d,W:%d,N:%d\n", + x * ts->widthFactor >> SHIFTBITS, + y * ts->heightFactor >> SHIFTBITS, + w, EN_NoiseFilter); + } else if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 0)) + && !(ts->useScreenRes)) { + I("status:Raw:F:%02d", i + 1); + I("Down,X:%d,Y:%d,W:%d,N:%d\n", + x, y, w, EN_NoiseFilter); + } + + if (ts->protocol_type == PROTOCOL_TYPE_B) + input_mt_slot(ts->input_dev, i); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, w); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, w); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, w); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y); + + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, i); + input_mt_sync(ts->input_dev); + } else { + ts->last_slot = i; + input_mt_report_slot_state + (ts->input_dev, + MT_TOOL_FINGER, 1); + } + + if (!ts->first_pressed) { + ts->first_pressed = 1; + I("S1@%d, %d\n", x, y); + } + + ts->pre_finger_data[i][0] = x; + ts->pre_finger_data[i][1] = y; + + if (ts->debug_log_level & BIT(1)) { + I("Finger %d=> X:%d,Y:%d,W:%d,", + i + 1, x, y, w); + I("Z:%d,F:%d,N:%d\n", + w, i + 1, EN_NoiseFilter); + } + ts->pre_finger_mask = + ts->pre_finger_mask + (1 << i); + + } else { + if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 0); + } + if (i == 0 && ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", + ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); + } + if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 1)) + && (ts->useScreenRes)) { + I("status:Screen:F:%02d,Up,X:%d,Y:%d\n", + i + 1, ts->pre_finger_data[i][0] + * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[i][1] + * ts->heightFactor >> SHIFTBITS); + } else if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 1)) + && !(ts->useScreenRes)) { + I("status:Raw:F:%02d,Up,X:%d,Y:%d\n", + i + 1, ts->pre_finger_data[i][0], + ts->pre_finger_data[i][1]); + } + } + } + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } else if ((hx_point_num != 0) + && ((tpd_key_old != 0x00) && (tpd_key == 0x00))) { + /*temp_x[0] = 0xFFFF;*/ + /*temp_y[0] = 0xFFFF;*/ + /*temp_x[1] = 0xFFFF;*/ + /*temp_y[1] = 0xFFFF;*/ + himax_ts_button_func(tpd_key, ts); + finger_on = 0; + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } else if (hx_point_num == 0) { + if (AA_press) { + /*leave event*/ + finger_on = 0; + AA_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(ts->input_dev); + + for (i = 0 ; i < ts->nFinger_support ; i++) { + if ((((ts->pre_finger_mask >> i) & 1) == 1) + && (ts->protocol_type == PROTOCOL_TYPE_B)) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 0); + } + } + if (ts->pre_finger_mask > 0) { + for (i = 0; i < ts->nFinger_support + && (ts->debug_log_level & BIT(3)) > 0; i++) { + if ((((ts->pre_finger_mask + >> i) & 1) == 1) + && (ts->useScreenRes)) { + I("status:%X,", 0); + I("Screen:F:%02d,", i + 1); + I("Up,X:%d,Y:%d\n", + ts->pre_finger_data[i][0] + * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[i][1] + * ts->heightFactor >> SHIFTBITS + ); + } else if ((((ts->pre_finger_mask + >> i) & 1) == 1) + && !(ts->useScreenRes)) { + I("status:%X,", 0); + I("Screen:F:%02d,", i + 1); + I("Up,X:%d,Y:%d\n", + ts->pre_finger_data[i][0], + ts->pre_finger_data[i][1]); + } + } + ts->pre_finger_mask = 0; + } + + if (ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); + } + + if (ts->debug_log_level & BIT(1)) + I("All Finger leave\n"); + +#ifdef HX_TP_PROC_DIAG + /*coordinate dump start*/ + if (coordinate_dump_enable == 1) { + do_gettimeofday(&t); + time_to_tm(t.tv_sec, 0, &broken); + snprintf(&coordinate_char[0], 15, + "%2d:%2d:%2d:%lu,", broken.tm_hour, + broken.tm_min, broken.tm_sec, + t.tv_usec / 1000); + + snprintf(&coordinate_char[15], 10, + "Touch up!"); + + coordinate_fn->f_op->write + (coordinate_fn, &coordinate_char[0], + 15 + (ic_data->HX_MAX_PT + 5) + * 2 * sizeof(char) * 5 + 2, + &coordinate_fn->f_pos); + } + /*coordinate dump end*/ +#endif + } else if (tpd_key != 0x00) { + himax_ts_button_func(tpd_key, ts); + finger_on = 1; + } else if ((tpd_key_old != 0x00) && (tpd_key == 0x00)) { + himax_ts_button_func(tpd_key, ts); + finger_on = 0; + } + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } + tpd_key_old = tpd_key; + +workqueue_out: + return; + +err_workqueue_out: + I("%s: Now reset the Touch chip.\n", __func__); + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true, false); +#endif + + goto workqueue_out; +} +enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) +{ + struct himax_ts_data *ts; + + ts = container_of(timer, struct himax_ts_data, timer); + queue_work(ts->himax_wq, &ts->work); + hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +#if defined(HX_USB_DETECT) +static void himax_cable_tp_status_handler_func(int connect_status) +{ + struct himax_ts_data *ts; + + I("Touch: cable change to %d\n", connect_status); + ts = private_ts; + if (ts->cable_config) { + if (!atomic_read(&ts->suspend_mode)) { + if ((!!connect_status) != ts->usb_connected) { + if (!!connect_status) { + ts->cable_config[1] = 0x01; + ts->usb_connected = 0x01; + } else { + ts->cable_config[1] = 0x00; + ts->usb_connected = 0x00; + } + + i2c_himax_master_write(ts->client, + ts->cable_config, + sizeof(ts->cable_config), + HIMAX_I2C_RETRY_TIMES); + + I("%s: Cable status change: 0x%2.2X\n", + __func__, ts->cable_config[1]); + } else + I("%s: Cable status is same, ignore.\n", + __func__); + } else { + if (connect_status) + ts->usb_connected = 0x01; + else + ts->usb_connected = 0x00; + I("%s: Cable status remembered: 0x%2.2X\n", + __func__, ts->usb_connected); + } + } +} + +static struct t_cable_status_notifier himax_cable_status_handler = { + .name = "usb_tp_connected", + .func = himax_cable_tp_status_handler_func, +}; + +#endif + +#if defined(HX_USB_DETECT2) +void himax_cable_detect_func(void) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + struct himax_ts_data *ts; + u32 connect_status = 0; + + connect_status = USB_Flag;/*upmu_is_chr_det();*/ + ts = private_ts; + /*I("Touch: cable status=%d, cable_config=%p, + usb_connected=%d\n", connect_status, + ts->cable_config, ts->usb_connected);*/ + + if (ts->cable_config) { + if ((!!connect_status) != ts->usb_connected) { + /*notify USB plug/unplug*/ + /*0x9008_8060 ==> 0x0000_0000/0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x60; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + if (!!connect_status) { + tmp_data[0] = 0x01; + ts->usb_connected = 0x01; + } else { + tmp_data[0] = 0x00; + ts->usb_connected = 0x00; + } + + himax_flash_write_burst(ts->client, tmp_addr, tmp_data); + + I("%s: Cable status change: 0x%2.2X\n", + __func__, ts->usb_connected); + } + /*else*/ + /*I("%s: Cable status is the same as previous one, + ignore.\n", __func__);*/ + + } +} +#endif + +#ifdef CONFIG_FB +int himax_fb_register(struct himax_ts_data *ts) +{ + int ret = 0; + + I(" %s in", __func__); + ts->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts->fb_notif); + if (ret) + E(" Unable to register fb_notifier: %d\n", ret); + + return ret; +} +#endif + +#ifdef HX_SMART_WAKEUP +void himax_set_SMWP_func(struct i2c_client *client, uint8_t SMWP_enable) +{ + uint8_t tmp_data[4]; + + if (SMWP_enable) { +SMWP_bit_retry: + himax_set_SMWP_enable(client, SMWP_enable); + msleep(20); + himax_get_SMWP_enable(client, tmp_data); +I("%s: Read SMWP bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", +__func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + if (tmp_data[0] != 0x01) { + I("%s: retry SMWP bit write data[0]=%x\n", + __func__, tmp_data[0]); + goto SMWP_bit_retry; + } + } +} + +static void himax_SMWP_work(struct work_struct *work) +{ + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, smwp_work.work); + I(" %s in", __func__); + + himax_set_SMWP_func(ts->client, ts->SMWP_enable); + +} +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP +static void himax_ts_flash_work_func(struct work_struct *work) +{ + himax_ts_flash_func(); +} +#endif + +#ifdef HX_TP_PROC_DIAG +static void himax_ts_diag_work_func(struct work_struct *work) +{ + himax_ts_diag_func(); +} +#endif + +bool himax_ts_init(struct himax_ts_data *ts) +{ + int ret = 0, err = 0; + struct himax_i2c_platform_data *pdata; + struct i2c_client *client; + + client = ts->client; + pdata = ts->pdata; + + I("%s: Start.\n", __func__); + + /* Set pinctrl in active state */ + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (ret < 0) + E("Failed to set pin in active state %d", ret); + } + + himax_burst_enable(client, 0); + + /*Get Himax IC Type / FW information / Calculate the point number */ + if (himax_check_chip_version(ts->client) == false) { + E("Himax chip doesn NOT EXIST"); + goto err_ic_package_failed; + } + if (himax_ic_package_check(ts->client) == false) { + E("Himax chip doesn NOT EXIST"); + goto err_ic_package_failed; + } + + if (pdata->virtual_key) + ts->button = pdata->virtual_key; +#ifdef HX_TP_PROC_FLASH_DUMP + ts->flash_wq = create_singlethread_workqueue("himax_flash_wq"); + if (!ts->flash_wq) { + E("%s: create flash workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_wq_failed; + } + + INIT_WORK(&ts->flash_work, himax_ts_flash_work_func); + + setSysOperation(0); + setFlashBuffer(); +#endif + +#ifdef HX_TP_PROC_DIAG + ts->himax_diag_wq = create_singlethread_workqueue("himax_diag"); + if (!ts->himax_diag_wq) { + E("%s: create diag workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_wq_failed; + } + INIT_DELAYED_WORK(&ts->himax_diag_delay_wrok, himax_ts_diag_work_func); +#endif + +himax_read_FW_ver(client); + +#ifdef HX_AUTO_UPDATE_FW + I(" %s in", __func__); + if (i_update_FW() <= 0) + I("FW NOT UPDATE=\n"); + else + I("Have new FW=UPDATE=\n"); +#endif + + /*Himax Power On and Load Config*/ + if (himax_loadSensorConfig(client, pdata) < 0) { + E("%s: Load Sesnsor config failed,unload driver.\n", + __func__); + goto err_detect_failed; + } + + calculate_point_number(); +#ifdef HX_TP_PROC_DIAG + setXChannel(ic_data->HX_RX_NUM); /*X channel*/ + setYChannel(ic_data->HX_TX_NUM); /*Y channel*/ + + setMutualBuffer(); + setMutualNewBuffer(); + setMutualOldBuffer(); + if (getMutualBuffer() == NULL) { + E("%s: mutual buffer allocate fail failed\n", __func__); + return false; + } +#ifdef HX_TP_PROC_2T2R + if (Is_2T2R) { + setXChannel_2(ic_data->HX_RX_NUM_2); /*X channel*/ + setYChannel_2(ic_data->HX_TX_NUM_2); /*Y channel*/ + + setMutualBuffer_2(); + + if (getMutualBuffer_2() == NULL) { + E("%s: mutual buffer 2 allocate fail failed\n", + __func__); + return false; + } + } +#endif +#endif +#ifdef CONFIG_OF + ts->power = pdata->power; +#endif + ts->pdata = pdata; + + ts->x_channel = ic_data->HX_RX_NUM; + ts->y_channel = ic_data->HX_TX_NUM; + ts->nFinger_support = ic_data->HX_MAX_PT; + /*calculate the i2c data size*/ + calcDataSize(ts->nFinger_support); + I("%s: calcDataSize complete\n", __func__); +#ifdef CONFIG_OF + ts->pdata->abs_pressure_min = 0; + ts->pdata->abs_pressure_max = 200; + ts->pdata->abs_width_min = 0; + ts->pdata->abs_width_max = 200; + pdata->cable_config[0] = 0x90; + pdata->cable_config[1] = 0x00; +#endif + ts->suspended = false; +#if defined(HX_USB_DETECT) || defined(HX_USB_DETECT2) + ts->usb_connected = 0x00; + ts->cable_config = pdata->cable_config; +#endif + ts->protocol_type = pdata->protocol_type; + I("%s: Use Protocol Type %c\n", __func__, + ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); + ret = himax_input_register(ts); + if (ret) { + E("%s: Unable to register %s input device\n", + __func__, ts->input_dev->name); + goto err_input_register_device_failed; + } +#ifdef HX_SMART_WAKEUP + ts->SMWP_enable = 0; + wakeup_source_init(&ts->ts_SMWP_wake_lock, + WAKE_LOCK_SUSPEND, HIMAX_common_NAME); + + ts->himax_smwp_wq = create_singlethread_workqueue("HMX_SMWP_WORK"); + if (!ts->himax_smwp_wq) { + E(" allocate himax_smwp_wq failed\n"); + err = -ENOMEM; + goto err_smwp_wq_failed; + } + INIT_DELAYED_WORK(&ts->smwp_work, himax_SMWP_work); +#endif +#ifdef HX_HIGH_SENSE + ts->HSEN_enable = 0; + ts->himax_hsen_wq = create_singlethread_workqueue("HMX_HSEN_WORK"); + if (!ts->himax_hsen_wq) { + E(" allocate himax_hsen_wq failed\n"); + err = -ENOMEM; + goto err_hsen_wq_failed; + } + INIT_DELAYED_WORK(&ts->hsen_work, himax_HSEN_func); +#endif + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_touch_proc_init(); +#endif + +#if defined(HX_USB_DETECT) + if (ts->cable_config) + cable_detect_register_notifier(&himax_cable_status_handler); +#endif + + err = himax_ts_register_interrupt(ts->client); + if (err) + goto err_register_interrupt_failed; + return true; + +err_register_interrupt_failed: +#ifdef HX_HIGH_SENSE +err_hsen_wq_failed: +#endif +#ifdef HX_SMART_WAKEUP +err_smwp_wq_failed: + wakeup_source_trash(&ts->ts_SMWP_wake_lock); +#endif +err_input_register_device_failed: + input_free_device(ts->input_dev); +err_detect_failed: +#ifdef HX_TP_PROC_FLASH_DUMP +err_create_wq_failed: +#endif +err_ic_package_failed: +return false; +} + +int himax_chip_common_probe(struct i2c_client *client, +const struct i2c_device_id *id) +{ + int err = 0; + struct himax_ts_data *ts; + struct himax_i2c_platform_data *pdata; + + /*Check I2C functionality*/ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + E("%s: i2c check functionality error\n", __func__); + err = -ENODEV; + goto err_check_functionality_failed; + } + + ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL); + if (ts == NULL) { + E("%s: allocate himax_ts_data failed\n", __func__); + err = -ENOMEM; + goto err_alloc_data_failed; + } + + i2c_set_clientdata(client, ts); + ts->client = client; + ts->dev = &client->dev; + mutex_init(&ts->rw_lock); + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (pdata == NULL) { /*Allocate Platform data space*/ + err = -ENOMEM; + goto err_dt_platform_data_fail; + } + + ic_data = kzalloc(sizeof(*ic_data), GFP_KERNEL); + if (ic_data == NULL) { /*Allocate IC data space*/ + err = -ENOMEM; + goto err_dt_ic_data_fail; + } + +#ifdef CONFIG_OF + /*DeviceTree Init Platform_data*/ + if (client->dev.of_node) { + err = himax_parse_dt(ts, pdata); + if (err < 0) { + I(" pdata is NULL for DT\n"); + goto err_alloc_dt_pdata_failed; + } + } +#endif + +#ifdef HX_RST_PIN_FUNC + ts->rst_gpio = pdata->gpio_reset; +#endif + + himax_gpio_power_config(ts->client, pdata); + + err = himax_ts_pinctrl_init(ts); + if (err || ts->ts_pinctrl == NULL) + E(" Pinctrl init failed\n"); + +#ifndef CONFIG_OF + if (pdata->power) { + err = pdata->power(1); + if (err < 0) { + E("%s: power on failed\n", __func__); + goto err_power_failed; + } + } +#endif + ts->pdata = pdata; + private_ts = ts; + + mutex_init(&ts->fb_mutex); + /* ts initialization is deferred till FB_UNBLACK event; + * probe is considered pending till then.*/ + ts->probe_done = false; +#ifdef CONFIG_FB + err = himax_fb_register(ts); + if (err) { + E("Falied to register fb notifier\n"); + err = -ENOMEM; + goto err_fb_notif_wq_create; + } +#endif + + return 0; + +#ifdef CONFIG_FB +err_fb_notif_wq_create: +#endif +#ifdef CONFIG_OF +err_alloc_dt_pdata_failed: +#else +err_power_failed: +err_get_platform_data_fail: +#endif + if (ts->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + devm_pinctrl_put(ts->ts_pinctrl); + ts->ts_pinctrl = NULL; + } else { + err = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_release); + if (err) + E("failed to select relase pinctrl state %d\n", + err); + } + } + kfree(ic_data); + +err_dt_ic_data_fail: + kfree(pdata); + +err_dt_platform_data_fail: + kfree(ts); + +err_alloc_data_failed: + +err_check_functionality_failed: + probe_fail_flag = 1; + return err; + +} + +int himax_chip_common_remove(struct i2c_client *client) +{ + struct himax_ts_data *ts = i2c_get_clientdata(client); + int ret; +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_touch_proc_deinit(); +#endif +#ifdef CONFIG_FB + if (fb_unregister_client(&ts->fb_notif)) { + dev_err(&client->dev, + "Error occurred while unregistering fb_notifier.\n"); + } +#endif + + if (!ts->use_irq) + hrtimer_cancel(&ts->timer); + + destroy_workqueue(ts->himax_wq); + + if (ts->protocol_type == PROTOCOL_TYPE_B) + input_mt_destroy_slots(ts->input_dev); + + input_unregister_device(ts->input_dev); + + if (ts->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + devm_pinctrl_put(ts->ts_pinctrl); + ts->ts_pinctrl = NULL; + } else { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_release); + if (ret) + E("failed to select relase pinctrl state %d\n", + ret); + } + } +#ifdef HX_SMART_WAKEUP + wakeup_source_trash(&ts->ts_SMWP_wake_lock); +#endif + kfree(ts); + + return 0; + +} + +int himax_chip_common_suspend(struct himax_ts_data *ts) +{ + int ret; + + if (ts->suspended) { + I("%s: Already suspended. Skipped.\n", __func__); + return 0; + + } else { + ts->suspended = true; + I("%s: enter\n", __func__); + } + +#ifdef HX_TP_PROC_FLASH_DUMP + if (getFlashDumpGoing()) { + I("[himax] %s: Flash dump is going,reject suspend\n", + __func__); + return 0; + } +#endif +#ifdef HX_TP_PROC_HITOUCH + if (hitouch_is_connect) { + I("[himax] %s: Hitouch connect,reject suspend\n", + __func__); + return 0; + } +#endif +#ifdef HX_SMART_WAKEUP + if (ts->SMWP_enable) { + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + FAKE_POWER_KEY_SEND = false; + I("[himax] %s: SMART_WAKEUP enable,reject suspend\n", + __func__); + return 0; + } +#endif +#ifdef HX_ESD_WORKAROUND + ESD_00_counter = 0; + ESD_00_Flag = 0; +#endif + if (!ts->use_irq) { + ret = cancel_work_sync(&ts->work); + if (ret) + himax_int_enable(ts->client->irq, 1); + } + + /*ts->first_pressed = 0;*/ + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_suspend); + if (ret < 0) + E("Failed to get idle pinctrl state %d\n", ret); + } + + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(0); + + return 0; +} + +int himax_chip_common_resume(struct himax_ts_data *ts) +{ + int retval; + + I("%s: enter\n", __func__); + + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(1); + + if (ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(ts->input_dev); + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_sync(ts->input_dev); + + if (ts->ts_pinctrl) { + retval = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (retval < 0) { + E("Cannot get default pinctrl state %d\n", retval); + goto err_pinctrl_select_resume; + } + } + + atomic_set(&ts->suspend_mode, 0); + + himax_int_enable(ts->client->irq, 1); + + ts->suspended = false; +#if defined(HX_USB_DETECT2) + ts->usb_connected = 0x00; + himax_cable_detect_func(); +#endif +#ifdef HX_SMART_WAKEUP + queue_delayed_work(ts->himax_smwp_wq, + &ts->smwp_work, msecs_to_jiffies(1000)); +#endif +#ifdef HX_HIGH_SENSE + queue_delayed_work(ts->himax_hsen_wq, + &ts->hsen_work, msecs_to_jiffies(1000)); +#endif + return 0; +err_pinctrl_select_resume: + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(0); + return retval; +} + diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h new file mode 100644 index 000000000000..41c97f7b5204 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_common.h @@ -0,0 +1,472 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef HIMAX_COMMON_H +#define HIMAX_COMMON_H + +#include "himax_platform.h" + +#include +/*#include */ +/*#include */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include +#endif + +#ifdef CONFIG_OF +#include +#endif +#define HIMAX_DRIVER_VER "0.3.1.0" + +#define FLASH_DUMP_FILE "/data/user/Flash_Dump.bin" +#define DIAG_COORDINATE_FILE "/sdcard/Coordinate_Dump.csv" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + +#define HX_TP_PROC_DIAG +#define HX_TP_PROC_REGISTER +#define HX_TP_PROC_DEBUG +#define HX_TP_PROC_FLASH_DUMP +#define HX_TP_PROC_SELF_TEST +#define HX_TP_PROC_RESET +#define HX_TP_PROC_SENSE_ON_OFF +/*#define HX_TP_PROC_2T2R*/ + +int himax_touch_proc_init(void); +void himax_touch_proc_deinit(void); +#endif + +/*===========Himax Option function=============*/ +/*#define HX_RST_PIN_FUNC*/ +#define HX_AUTO_UPDATE_FW +/*#define HX_HIGH_SENSE*/ +/*#define HX_SMART_WAKEUP*/ +/*#define HX_USB_DETECT*/ +/*#define HX_ESD_WORKAROUND*/ +/*#define HX_USB_DETECT2*/ +/*#define HX_EN_SEL_BUTTON*//* Support Self Virtual key ,default is close*/ +#define HX_EN_MUT_BUTTON/* Support Mutual Virtual Key ,default is close*/ +/*#define HX_EN_CHECK_PATCH*/ + +#define HX_KEY_MAX_COUNT 4 +#define DEFAULT_RETRY_CNT 3 + +#define HX_VKEY_0 KEY_BACK +#define HX_VKEY_1 KEY_HOME +#define HX_VKEY_2 KEY_RESERVED +#define HX_VKEY_3 KEY_RESERVED +#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3} + +#define SHIFTBITS 5 +/*#define FLASH_SIZE 131072*/ +#define FW_SIZE_60k 61440 +#define FW_SIZE_64k 65536 +#define FW_SIZE_124k 126976 +#define FW_SIZE_128k 131072 + +struct himax_ic_data { + int vendor_fw_ver; + int vendor_config_ver; + int vendor_sensor_id; + int HX_RX_NUM; + int HX_TX_NUM; + int HX_BT_NUM; + int HX_X_RES; + int HX_Y_RES; + int HX_MAX_PT; + bool HX_XY_REVERSE; + bool HX_INT_IS_EDGE; +#ifdef HX_TP_PROC_2T2R + int HX_RX_NUM_2; + int HX_TX_NUM_2; +#endif +}; + +struct himax_virtual_key { + int index; + int keycode; + int x_range_min; + int x_range_max; + int y_range_min; + int y_range_max; +}; + +struct himax_config { + uint8_t default_cfg; + uint8_t sensor_id; + uint8_t fw_ver; + uint16_t length; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + uint8_t c1[11]; + uint8_t c2[11]; + uint8_t c3[11]; + uint8_t c4[11]; + uint8_t c5[11]; + uint8_t c6[11]; + uint8_t c7[11]; + uint8_t c8[11]; + uint8_t c9[11]; + uint8_t c10[11]; + uint8_t c11[11]; + uint8_t c12[11]; + uint8_t c13[11]; + uint8_t c14[11]; + uint8_t c15[11]; + uint8_t c16[11]; + uint8_t c17[11]; + uint8_t c18[17]; + uint8_t c19[15]; + uint8_t c20[5]; + uint8_t c21[11]; + uint8_t c22[4]; + uint8_t c23[3]; + uint8_t c24[3]; + uint8_t c25[4]; + uint8_t c26[2]; + uint8_t c27[2]; + uint8_t c28[2]; + uint8_t c29[2]; + uint8_t c30[2]; + uint8_t c31[2]; + uint8_t c32[2]; + uint8_t c33[2]; + uint8_t c34[2]; + uint8_t c35[3]; + uint8_t c36[5]; + uint8_t c37[5]; + uint8_t c38[9]; + uint8_t c39[14]; + uint8_t c40[159]; + uint8_t c41[99]; +}; + +struct himax_ts_data { + bool suspended; + bool probe_done; + struct mutex fb_mutex; + struct mutex rw_lock; + atomic_t suspend_mode; + uint8_t x_channel; + uint8_t y_channel; + uint8_t useScreenRes; + uint8_t diag_command; + uint8_t protocol_type; + uint8_t first_pressed; + uint8_t coord_data_size; + uint8_t area_data_size; + uint8_t raw_data_frame_size; + uint8_t raw_data_nframes; + uint8_t nFinger_support; + uint8_t irq_enabled; + uint8_t diag_self[50]; + uint16_t finger_pressed; + uint16_t last_slot; + uint16_t pre_finger_mask; + uint32_t debug_log_level; + uint32_t widthFactor; + uint32_t heightFactor; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + + int use_irq; + int (*power)(int on); + int pre_finger_data[10][2]; + + struct device *dev; + struct workqueue_struct *himax_wq; + struct work_struct work; + struct input_dev *input_dev; + struct hrtimer timer; + struct i2c_client *client; + struct himax_i2c_platform_data *pdata; + struct himax_virtual_key *button; + +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + struct workqueue_struct *flash_wq; + struct work_struct flash_work; +#endif + +#ifdef HX_RST_PIN_FUNC + int rst_gpio; +#endif + +#ifdef HX_TP_PROC_DIAG + struct workqueue_struct *himax_diag_wq; + struct delayed_work himax_diag_delay_wrok; +#endif +#ifdef HX_SMART_WAKEUP + uint8_t SMWP_enable; + uint8_t gesture_cust_en[16]; + struct wakeup_source ts_SMWP_wake_lock; + struct workqueue_struct *himax_smwp_wq; + struct delayed_work smwp_work; +#endif + +#ifdef HX_HIGH_SENSE + uint8_t HSEN_enable; + struct workqueue_struct *himax_hsen_wq; + struct delayed_work hsen_work; +#endif + +#if defined(HX_USB_DETECT) || defined(HX_USB_DETECT2) + uint8_t usb_connected; + uint8_t *cable_config; +#endif + + /* pinctrl data */ + struct pinctrl *ts_pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspend; + struct pinctrl_state *pinctrl_state_release; +}; + +#define HX_CMD_NOP 0x00 +#define HX_CMD_SETMICROOFF 0x35 +#define HX_CMD_SETROMRDY 0x36 +#define HX_CMD_TSSLPIN 0x80 +#define HX_CMD_TSSLPOUT 0x81 +#define HX_CMD_TSSOFF 0x82 +#define HX_CMD_TSSON 0x83 +#define HX_CMD_ROE 0x85 +#define HX_CMD_RAE 0x86 +#define HX_CMD_RLE 0x87 +#define HX_CMD_CLRES 0x88 +#define HX_CMD_TSSWRESET 0x9E +#define HX_CMD_SETDEEPSTB 0xD7 +#define HX_CMD_SET_CACHE_FUN 0xDD +#define HX_CMD_SETIDLE 0xF2 +#define HX_CMD_SETIDLEDELAY 0xF3 +#define HX_CMD_SELFTEST_BUFFER 0x8D +#define HX_CMD_MANUALMODE 0x42 +#define HX_CMD_FLASH_ENABLE 0x43 +#define HX_CMD_FLASH_SET_ADDRESS 0x44 +#define HX_CMD_FLASH_WRITE_REGISTER 0x45 +#define HX_CMD_FLASH_SET_COMMAND 0x47 +#define HX_CMD_FLASH_WRITE_BUFFER 0x48 +#define HX_CMD_FLASH_PAGE_ERASE 0x4D +#define HX_CMD_FLASH_SECTOR_ERASE 0x4E +#define HX_CMD_CB 0xCB +#define HX_CMD_EA 0xEA +#define HX_CMD_4A 0x4A +#define HX_CMD_4F 0x4F +#define HX_CMD_B9 0xB9 +#define HX_CMD_76 0x76 + +enum input_protocol_type { + PROTOCOL_TYPE_A = 0x00, + PROTOCOL_TYPE_B = 0x01, +}; + +#ifdef HX_HIGH_SENSE +void himax_set_HSEN_func(struct i2c_client *client, uint8_t HSEN_enable); +#endif + +#ifdef HX_SMART_WAKEUP +#define GEST_PTLG_ID_LEN (4) +#define GEST_PTLG_HDR_LEN (4) +#define GEST_PTLG_HDR_ID1 (0xCC) +#define GEST_PTLG_HDR_ID2 (0x44) +#define GEST_PT_MAX_NUM (128) + +#ifdef HX_GESTURE_TRACK +static int gest_pt_cnt; +static int gest_pt_x[GEST_PT_MAX_NUM]; +static int gest_pt_y[GEST_PT_MAX_NUM]; +static int gest_start_x, gest_start_y, gest_end_x, gest_end_y; +static int gest_width, gest_height, gest_mid_x, gest_mid_y; +static int gn_gesture_coor[16]; +#endif + +void himax_set_SMWP_func(struct i2c_client *client, uint8_t SMWP_enable); +extern bool FAKE_POWER_KEY_SEND; + + enum gesture_event_type { + EV_GESTURE_01 = 0x01, + EV_GESTURE_02, + EV_GESTURE_03, + EV_GESTURE_04, + EV_GESTURE_05, + EV_GESTURE_06, + EV_GESTURE_07, + EV_GESTURE_08, + EV_GESTURE_09, + EV_GESTURE_10, + EV_GESTURE_11, + EV_GESTURE_12, + EV_GESTURE_13, + EV_GESTURE_14, + EV_GESTURE_15, + EV_GESTURE_PWR = 0x80, + }; + +#define KEY_CUST_01 251 +#define KEY_CUST_02 252 +#define KEY_CUST_03 253 +#define KEY_CUST_04 254 +#define KEY_CUST_05 255 +#define KEY_CUST_06 256 +#define KEY_CUST_07 257 +#define KEY_CUST_08 258 +#define KEY_CUST_09 259 +#define KEY_CUST_10 260 +#define KEY_CUST_11 261 +#define KEY_CUST_12 262 +#define KEY_CUST_13 263 +#define KEY_CUST_14 264 +#define KEY_CUST_15 265 +#endif + +#ifdef HX_ESD_WORKAROUND + extern u8 HX_ESD_RESET_ACTIVATE; +#endif + +extern int irq_enable_count; + +#ifdef QCT +irqreturn_t himax_ts_thread(int irq, void *ptr); +int himax_input_register(struct himax_ts_data *ts); +#endif + +int himax_chip_common_probe(struct i2c_client *client, +const struct i2c_device_id *id); +int himax_chip_common_remove(struct i2c_client *client); +int himax_chip_common_suspend(struct himax_ts_data *ts); +int himax_chip_common_resume(struct himax_ts_data *ts); +int himax_loadSensorConfig(struct i2c_client *client, +struct himax_i2c_platform_data *pdata); + +#ifdef HX_USB_DETECT2 +/*extern kal_bool upmu_is_chr_det(void);*/ +void himax_cable_detect_func(void); +#endif + +#ifdef HX_AUTO_UPDATE_FW +extern unsigned long FW_VER_MAJ_FLASH_ADDR; +extern unsigned long FW_VER_MIN_FLASH_ADDR; +extern unsigned long CFG_VER_MAJ_FLASH_ADDR; +extern unsigned long CFG_VER_MIN_FLASH_ADDR; +#endif +extern unsigned long FW_VER_MAJ_FLASH_LENG; +extern unsigned long FW_VER_MIN_FLASH_LENG; +extern unsigned long CFG_VER_MAJ_FLASH_LENG; +extern unsigned long CFG_VER_MIN_FLASH_LENG; +extern unsigned char IC_TYPE; +extern unsigned char IC_CHECKSUM; + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +extern int himax_touch_proc_init(void); +extern void himax_touch_proc_deinit(void); +/*PROC-START*/ +#ifdef HX_TP_PROC_FLASH_DUMP +extern void himax_ts_flash_func(void); +extern void setFlashBuffer(void); +extern bool getFlashDumpGoing(void); +extern uint8_t getSysOperation(void); +extern void setSysOperation(uint8_t operation); +#endif + +#ifdef HX_TP_PROC_HITOUCH +extern bool hitouch_is_connect; +#endif + +#ifdef HX_TP_PROC_DIAG + extern int touch_monitor_stop_flag; + + extern int touch_monitor_stop_limit; + + extern void himax_ts_diag_func(void); + + extern int16_t *getMutualBuffer(void); + extern int16_t *getMutualNewBuffer(void); + extern int16_t *getMutualOldBuffer(void); + extern int16_t *getSelfBuffer(void); + extern uint8_t getXChannel(void); + extern uint8_t getYChannel(void); + extern uint8_t getDiagCommand(void); + extern void setXChannel(uint8_t x); + extern void setYChannel(uint8_t y); + extern void setMutualBuffer(void); + extern void setMutualNewBuffer(void); + extern void setMutualOldBuffer(void); + extern uint8_t coordinate_dump_enable; + extern struct file *coordinate_fn; + extern uint8_t diag_coor[128]; +#ifdef HX_TP_PROC_2T2R + extern int16_t *getMutualBuffer_2(void); + extern uint8_t getXChannel_2(void); + extern uint8_t getYChannel_2(void); + extern void setXChannel_2(uint8_t x); + extern void setYChannel_2(uint8_t y); + extern void setMutualBuffer_2(void); +#endif +#endif +/*PROC-END*/ +#endif + +#ifdef HX_USB_DETECT2 + extern bool USB_Flag; +#endif +#ifdef HX_ESD_WORKAROUND + extern void HX_report_ESD_event(void); + unsigned char ESD_00_counter = 0; + unsigned char ESD_00_Flag = 0; +#endif +bool himax_ts_init(struct himax_ts_data *ts); + +#endif + diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.c b/drivers/input/touchscreen/hxchipset/himax_debug.c new file mode 100644 index 000000000000..55cc7ca92e4c --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_debug.c @@ -0,0 +1,2205 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_debug.h" +#include "himax_ic.h" + +/*struct himax_debug_data* debug_data;*/ + +#ifdef HX_TP_PROC_DIAG +#ifdef HX_TP_PROC_2T2R +int HX_RX_NUM_2; +int HX_TX_NUM_2; +#endif +int touch_monitor_stop_flag; +int touch_monitor_stop_limit = 5; +uint8_t g_diag_arr_num; +#endif + +#ifdef HX_ESD_WORKAROUND +u8 HX_ESD_RESET_ACTIVATE; +#endif + +#ifdef HX_SMART_WAKEUP +bool FAKE_POWER_KEY_SEND; +#endif + +/*======================================================== + +Segment : Himax PROC Debug Function + +==========================================================*/ +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + +static ssize_t himax_vendor_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + ret += snprintf(temp_buf, len, + "%s_FW:%#x_CFG:%#x_SensorId:%#x\n", + HIMAX_common_NAME, ic_data->vendor_fw_ver, + ic_data->vendor_config_ver, ic_data->vendor_sensor_id); + + HX_PROC_SEND_FLAG = 1; + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + } else + HX_PROC_SEND_FLAG = 0; + + return ret; +} + +const struct file_operations himax_proc_vendor_ops = { + .owner = THIS_MODULE, + .read = himax_vendor_read, +}; + +static ssize_t himax_attn_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + struct himax_ts_data *ts_data; + char *temp_buf; + + ts_data = private_ts; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + ret += snprintf(temp_buf, len, "attn = %x\n", + himax_int_gpio_read(ts_data->pdata->gpio_irq)); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + + return ret; +} + +const struct file_operations himax_proc_attn_ops = { + .owner = THIS_MODULE, + .read = himax_attn_read, +}; + +static ssize_t himax_int_en_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + ret += snprintf(temp_buf, len-1, "%d ", ts->irq_enabled); + ret += snprintf(temp_buf, 1, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + return ret; +} + +static ssize_t himax_int_en_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[12] = {0}; + int value, ret = 0; + + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + return -EFAULT; + + if (buf_tmp[0] == '0') + value = false; + else if (buf_tmp[0] == '1') + value = true; + else + return -EINVAL; + + if (value) { + if (ic_data->HX_INT_IS_EDGE) { +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + himax_int_enable(ts->client->irq, 1); +#else + /*mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_TYPE); + mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);*/ + mt_eint_registration(ts->client->irq, + EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1); +#endif +#endif +#ifdef QCT + ret = request_threaded_irq(ts->client->irq, + NULL, himax_ts_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + ts->client->name, ts); +#endif + } else { +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + himax_int_enable(ts->client->irq, 1); +#else + /*mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_TYPE); + mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);*/ + mt_eint_registration(ts->client->irq, + EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1); +#endif +#endif +#ifdef QCT + ret = request_threaded_irq(ts->client->irq, + NULL, himax_ts_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + ts->client->name, ts); +#endif + } + if (ret == 0) { + ts->irq_enabled = 1; + irq_enable_count = 1; + } + } else { + himax_int_enable(ts->client->irq, 0); + free_irq(ts->client->irq, ts); + ts->irq_enabled = 0; + } + + return len; +} + +const struct file_operations himax_proc_int_en_ops = { + .owner = THIS_MODULE, + .read = himax_int_en_read, + .write = himax_int_en_write, +}; + +static ssize_t himax_layout_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_max); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_y_min); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_y_max); + ret += snprintf(temp_buf, len, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + + return ret; +} + +static ssize_t himax_layout_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[5]; + int i = 0, j = 0, k = 0, ret; + unsigned long value; + int layout[4] = {0}; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + for (i = 0 ; i < 20 ; i++) { + if (buf[i] == ',' || buf[i] == '\n') { + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + if (i - j <= 5) + memcpy(buf_tmp, buf + j, i - j); + else { + I("buffer size is over 5 char\n"); + return len; + } + j = i + 1; + if (k < 4) { + ret = kstrtoul(buf_tmp, 10, &value); + layout[k++] = value; + } + } + } + if (k == 4) { + ts->pdata->abs_x_min = layout[0]; + ts->pdata->abs_x_max = layout[1]; + ts->pdata->abs_y_min = layout[2]; + ts->pdata->abs_y_max = layout[3]; + I("%d, %d, %d, %d\n", ts->pdata->abs_x_min, + ts->pdata->abs_x_max, ts->pdata->abs_y_min, + ts->pdata->abs_y_max); + input_unregister_device(ts->input_dev); + himax_input_register(ts); + } else { + I("ERR@%d, %d, %d, %d\n", ts->pdata->abs_x_min, + ts->pdata->abs_x_max, ts->pdata->abs_y_min, + ts->pdata->abs_y_max); + } + return len; +} + +const struct file_operations himax_proc_layout_ops = { + .owner = THIS_MODULE, + .read = himax_layout_read, + .write = himax_layout_write, +}; + +static ssize_t himax_debug_level_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts_data; + size_t ret = 0; + char *temp_buf; + + ts_data = private_ts; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + ret += snprintf(temp_buf, len, "%d\n", + ts_data->debug_log_level); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + + return ret; +} + +static ssize_t himax_debug_level_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts; + char buf_tmp[11]; + int i; + + ts = private_ts; + + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + return -EFAULT; + + ts->debug_log_level = 0; + for (i = 0 ; i < len - 1 ; i++) { + if (buf_tmp[i] >= '0' && buf_tmp[i] <= '9') + ts->debug_log_level |= (buf_tmp[i] - '0'); + else if (buf_tmp[i] >= 'A' && buf_tmp[i] <= 'F') + ts->debug_log_level |= (buf_tmp[i]-'A' + 10); + else if (buf_tmp[i] >= 'a' && buf_tmp[i] <= 'f') + ts->debug_log_level |= (buf_tmp[i] - 'a' + 10); + + if (i != len - 2) + ts->debug_log_level <<= 4; + } + + if (ts->debug_log_level & BIT(3)) { + if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 && + (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 && + (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { + ts->widthFactor = + (ts->pdata->screenWidth << SHIFTBITS) + / (ts->pdata->abs_x_max - ts->pdata->abs_x_min); + ts->heightFactor = + (ts->pdata->screenHeight << SHIFTBITS) + / (ts->pdata->abs_y_max - ts->pdata->abs_y_min); + if (ts->widthFactor > 0 && ts->heightFactor > 0) + ts->useScreenRes = 1; + else { + ts->heightFactor = 0; + ts->widthFactor = 0; + ts->useScreenRes = 0; + } + } else + I("Enable finger debug with raw position mode!\n"); + } else { + ts->useScreenRes = 0; + ts->widthFactor = 0; + ts->heightFactor = 0; + } + + return len; +} + +const struct file_operations himax_proc_debug_level_ops = { + .owner = THIS_MODULE, + .read = himax_debug_level_read, + .write = himax_debug_level_write, +}; + +#ifdef HX_TP_PROC_REGISTER +static ssize_t himax_proc_register_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + uint16_t loop_i; + uint8_t data[128]; + char *temp_buf; + + memset(data, 0x00, sizeof(data)); + + I("himax_register_show: %x,%x,%x,%x\n", register_command[0], + register_command[1], register_command[2], register_command[3]); + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + himax_register_read(private_ts->client, + register_command, 1, data); + + ret += snprintf(temp_buf, len, "command: %x,%x,%x,%x\n", + register_command[0], register_command[1], + register_command[2], register_command[3]); + + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + ret += snprintf(temp_buf + ret, + sizeof(data[loop_i]), "0x%2.2X ", data[loop_i]); + if ((loop_i % 16) == 15) + ret += snprintf(temp_buf + ret, 1, "\n"); + } + ret += snprintf(temp_buf + ret, len, "\n"); + HX_PROC_SEND_FLAG = 1; + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + } else + HX_PROC_SEND_FLAG = 0; + return ret; +} + +static ssize_t himax_proc_register_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[16], length = 0; + unsigned long result = 0; + uint8_t loop_i = 0; + uint16_t base = 5; + uint8_t write_da[128]; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + memset(write_da, 0x0, sizeof(write_da)); + + I("himax %s\n", buf); + + if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') { + + if (buf[2] == 'x') { + memcpy(buf_tmp, buf + 3, 8); + if (!kstrtoul(buf_tmp, 16, &result)) { + register_command[0] = + (uint8_t)result; + register_command[1] = + (uint8_t)(result >> 8); + register_command[2] = + (uint8_t)(result >> 16); + register_command[3] = + (uint8_t)(result >> 24); + } + base = 11; + I("CMD: %x,%x,%x,%x\n", register_command[0], + register_command[1], register_command[2], + register_command[3]); + + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + if (buf[base] == '\n') { + if (buf[0] == 'w') { + himax_register_write + (private_ts->client, + register_command + , 1, write_da); + I("CMD:%x, %x, %x, %x,len=%d\n", + write_da[0], write_da[1], + write_da[2], write_da[3], + length); + } + I("\n"); + return len; + } + if (buf[base + 1] == 'x') { + buf_tmp[10] = '\n'; + buf_tmp[11] = '\0'; + memcpy(buf_tmp, buf + base + 2, 8); + if (!kstrtoul(buf_tmp, 16, &result)) { + write_da[loop_i] = + (uint8_t)result; + write_da[loop_i+1] = + (uint8_t)(result >> 8); + write_da[loop_i+2] = + (uint8_t)(result >> 16); + write_da[loop_i+3] = + (uint8_t)(result >> 24); + } + length += 4; + } + base += 10; + } + } + } + return len; +} + +const struct file_operations himax_proc_register_ops = { + .owner = THIS_MODULE, + .read = himax_proc_register_read, + .write = himax_proc_register_write, +}; +#endif + +#ifdef HX_TP_PROC_DIAG +int16_t *getMutualBuffer(void) +{ + return diag_mutual; +} +int16_t *getMutualNewBuffer(void) +{ + return diag_mutual_new; +} +int16_t *getMutualOldBuffer(void) +{ + return diag_mutual_old; +} +int16_t *getSelfBuffer(void) +{ + return &diag_self[0]; +} +uint8_t getXChannel(void) +{ + return x_channel; +} +uint8_t getYChannel(void) +{ + return y_channel; +} +uint8_t getDiagCommand(void) +{ + return diag_command; +} +void setXChannel(uint8_t x) +{ + x_channel = x; +} +void setYChannel(uint8_t y) +{ + y_channel = y; +} +void setMutualBuffer(void) +{ + diag_mutual = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} +void setMutualNewBuffer(void) +{ + diag_mutual_new = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} +void setMutualOldBuffer(void) +{ + diag_mutual_old = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} + +#ifdef HX_TP_PROC_2T2R +int16_t *getMutualBuffer_2(void) +{ + return diag_mutual_2; +} +uint8_t getXChannel_2(void) +{ + return x_channel_2; +} +uint8_t getYChannel_2(void) +{ + return y_channel_2; +} +void setXChannel_2(uint8_t x) +{ + x_channel_2 = x; +} +void setYChannel_2(uint8_t y) +{ + y_channel_2 = y; +} +void setMutualBuffer_2(void) +{ + diag_mutual_2 = kzalloc + (x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL); +} +#endif + +static ssize_t himax_diag_arrange_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + /*struct himax_ts_data *ts = private_ts;*/ + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + g_diag_arr_num = buf[0] - '0'; + I("%s: g_diag_arr_num = %d\n", __func__, g_diag_arr_num); + + return len; +} + +const struct file_operations himax_proc_diag_arrange_ops = { + .owner = THIS_MODULE, + .write = himax_diag_arrange_write, +}; + +static void himax_diag_arrange_print +(struct seq_file *s, int i, int j, int transpose) +{ + if (transpose) + seq_printf(s, "%6d", diag_mutual[j + i * x_channel]); + else + seq_printf(s, "%6d", diag_mutual[i + j * x_channel]); +} + +static void himax_diag_arrange_inloop +(struct seq_file *s, int in_init, bool transpose, int j) +{ + int i; + int in_max = 0; + + if (transpose) + in_max = y_channel; + else + in_max = x_channel; + + if (in_init > 0) { + for (i = in_init - 1 ; i >= 0 ; i--) + himax_diag_arrange_print(s, i, j, transpose); + } else { + for (i = 0 ; i < in_max ; i++) + himax_diag_arrange_print(s, i, j, transpose); + } +} + +static void himax_diag_arrange_outloop +(struct seq_file *s, int transpose, int out_init, int in_init) +{ + int j; + int out_max = 0; + + if (transpose) + out_max = x_channel; + else + out_max = y_channel; + + if (out_init > 0) { + for (j = out_init - 1 ; j >= 0 ; j--) { + himax_diag_arrange_inloop(s, in_init, transpose, j); + seq_printf(s, " %5d\n", diag_self[j]); + } + } else { + for (j = 0 ; j < out_max ; j++) { + himax_diag_arrange_inloop(s, in_init, transpose, j); + seq_printf(s, " %5d\n", diag_self[j]); + } + } +} + +static void himax_diag_arrange(struct seq_file *s) +{ + int bit2, bit1, bit0; + int i; + + bit2 = g_diag_arr_num >> 2; + bit1 = g_diag_arr_num >> 1 & 0x1; + bit0 = g_diag_arr_num & 0x1; + + if (g_diag_arr_num < 4) { + himax_diag_arrange_outloop(s, + bit2, bit1 * y_channel, bit0 * x_channel); + + for (i = y_channel ; i < x_channel + y_channel ; i++) + seq_printf(s, "%6d", diag_self[i]); + + } else { + himax_diag_arrange_outloop(s, + bit2, bit1 * x_channel, bit0 * y_channel); + + for (i = x_channel ; i < x_channel + y_channel ; i++) + seq_printf(s, "%6d", diag_self[i]); + + } +} + +static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos >= 1) + return NULL; + return (void *)((unsigned long) *pos + 1); +} + +static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return NULL; +} +static void himax_diag_seq_stop(struct seq_file *s, void *v) +{ +} +static int himax_diag_seq_read(struct seq_file *s, void *v) +{ + size_t count = 0; + int32_t loop_i;/*loop_j*/ + uint16_t mutual_num, self_num, width; + +#ifdef HX_TP_PROC_2T2R + if (Is_2T2R && diag_command == 4) { + mutual_num = x_channel_2 * y_channel_2; + /*don't add KEY_COUNT*/ + self_num = x_channel_2 + y_channel_2; + width = x_channel_2; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", + x_channel_2, y_channel_2); + } else +#endif + { + mutual_num = x_channel * y_channel; + /*don't add KEY_COUNT*/ + self_num = x_channel + y_channel; + width = x_channel; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", + x_channel, y_channel); + } + + /* start to show out the raw data in adb shell*/ + if (diag_command >= 1 && diag_command <= 6) { + if (diag_command <= 3) { + himax_diag_arrange(s); + seq_puts(s, "\n\n"); +#ifdef HX_EN_SEL_BUTTON + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < HX_BT_NUM ; loop_i++) + seq_printf(s, "%6d", + diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]); +#endif +#ifdef HX_TP_PROC_2T2R + } else if (Is_2T2R && diag_command == 4) { + for (loop_i = 0 ; loop_i < mutual_num ; loop_i++) { + seq_printf(s, "%4d", diag_mutual_2[loop_i]); + if ((loop_i % width) == (width - 1)) + seq_printf(s, " %6d\n", + diag_self[width + loop_i / width]); + } + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < width ; loop_i++) { + seq_printf(s, "%6d", diag_self[loop_i]); + if (((loop_i) % width) == (width - 1)) + seq_putc(s, '\n'); + } +#ifdef HX_EN_SEL_BUTTON + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < HX_BT_NUM ; loop_i++) { + seq_printf(s, "%4d", + diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]); + } +#endif +#endif + } else if (diag_command > 4) { + for (loop_i = 0 ; loop_i < self_num ; loop_i++) { + seq_printf(s, "%4d", diag_self[loop_i]); + if (((loop_i - mutual_num) % width) + == (width - 1)) { + seq_putc(s, '\n'); + } + } + } else { + for (loop_i = 0 ; loop_i < mutual_num ; loop_i++) { + seq_printf(s, "%4d", diag_mutual[loop_i]); + if ((loop_i % width) == (width - 1)) + seq_putc(s, '\n'); + } + } + seq_puts(s, "ChannelEnd"); + seq_putc(s, '\n'); + } else if (diag_command == 7) { + for (loop_i = 0; loop_i < 128 ; loop_i++) { + if ((loop_i % 16) == 0) + seq_puts(s, "LineStart:"); + seq_printf(s, "%4d", diag_coor[loop_i]); + if ((loop_i % 16) == 15) + seq_putc(s, '\n'); + } + } else if (diag_command == 9 || + diag_command == 91 || diag_command == 92) { + + himax_diag_arrange(s); + seq_putc(s, '\n'); + } + + return count; +} +const struct seq_operations himax_diag_seq_ops = { + .start = himax_diag_seq_start, + .next = himax_diag_seq_next, + .stop = himax_diag_seq_stop, + .show = himax_diag_seq_read, +}; +static int himax_diag_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &himax_diag_seq_ops); +}; +bool DSRAM_Flag = false; + +/*DSRAM thread*/ +void himax_ts_diag_func(void) +{ + int i = 0, j = 0; + unsigned int index = 0; + int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; + uint8_t info_data[total_size]; + int16_t *mutual_data; + int16_t *mutual_data_new; + int16_t *mutual_data_old; + int16_t new_data; + + himax_burst_enable(private_ts->client, 1); + if (diag_command == 9 || diag_command == 91) { + mutual_data = getMutualBuffer(); + } else if (diag_command == 92) { + mutual_data = getMutualBuffer(); + mutual_data_new = getMutualNewBuffer(); + mutual_data_old = getMutualOldBuffer(); + } + himax_get_DSRAM_data(private_ts->client, info_data); + + index = 0; + for (i = 0 ; i < ic_data->HX_TX_NUM ; i++) { + for (j = 0 ; j < ic_data->HX_RX_NUM ; j++) { + new_data = (short)(info_data[index + 1] + << 8 | info_data[index]); + if (diag_command == 9) { + mutual_data[i * ic_data->HX_RX_NUM + j] + = new_data; + /*Keep max data for 100 frame*/ + } else if (diag_command == 91) { + if (mutual_data[i * ic_data->HX_RX_NUM + j] + < new_data) { + mutual_data[i * ic_data->HX_RX_NUM + j] + = new_data; + } + /*Cal data for [N]-[N-1] frame*/ + } else if (diag_command == 92) { + mutual_data_new[i * ic_data->HX_RX_NUM + j] + = new_data; + + mutual_data[i * ic_data->HX_RX_NUM + j] = + mutual_data_new[i * ic_data->HX_RX_NUM + j] - + mutual_data_old[i * ic_data->HX_RX_NUM + j]; + } + index += 2; + } + } + /*copy N data to N-1 array*/ + if (diag_command == 92) { + memcpy(mutual_data_old, mutual_data_new, + x_channel * y_channel * sizeof(int16_t)); + } + + diag_max_cnt++; + if (diag_command == 9 || diag_command == 92) { + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 1/10*HZ); + } else if (diag_command == 91) { + if (diag_max_cnt > 100) {/*count for 100 frame*/ + /*Clear DSRAM flag*/ + DSRAM_Flag = false; + + /*Enable ISR*/ + himax_int_enable(private_ts->client->irq, 1); + + /*===================================== + test result command : 0x8002_0324 ==> 0x00 + =====================================*/ + himax_diag_register_set(private_ts->client, 0x00); + } else { + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 1 / 10 * HZ); + } + } +} + +static ssize_t himax_diag_write +(struct file *filp, const char __user *buff, size_t len, loff_t *data) +{ + char messages[80] = {0}; + + uint8_t command[2] = {0x00, 0x00}; + uint8_t receive[1]; + + memset(receive, 0x00, sizeof(receive)); + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(messages, buff, len)) + return -EFAULT; + + if (messages[1] == 0x0A) + diag_command = messages[0] - '0'; + else + diag_command = (messages[0] - '0') * 10 + (messages[1] - '0'); + + + I("[Himax]diag_command=0x%x\n", diag_command); + if (diag_command < 0x04) { + if (DSRAM_Flag) { + /*1. Clear DSRAM flag*/ + DSRAM_Flag = false; + + /*2. Stop DSRAM thread*/ + cancel_delayed_work_sync + (&private_ts->himax_diag_delay_wrok); + + /*3. Enable ISR*/ + himax_int_enable(private_ts->client->irq, 1); + } + command[0] = diag_command; + himax_diag_register_set(private_ts->client, command[0]); + /*coordinate dump start*/ + } else if (diag_command == 0x09 || + diag_command == 91 || diag_command == 92) { + + diag_max_cnt = 0; + /*Set data 0 everytime*/ + memset(diag_mutual, 0x00, + x_channel * y_channel * sizeof(int16_t)); + + /*1. Disable ISR*/ + himax_int_enable(private_ts->client->irq, 0); + + /*2. Start DSRAM thread*/ + /*himax_diag_register_set(private_ts->client, 0x0A);*/ + + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 2 * HZ / 100); + + I("%s: Start get raw data in DSRAM\n", __func__); + + /*3. Set DSRAM flag*/ + DSRAM_Flag = true; + } else { + command[0] = 0x00; + himax_diag_register_set(private_ts->client, command[0]); + E("[Himax]Diag command error!diag_command=0x%x\n", + diag_command); + } + return len; +} + +const struct file_operations himax_proc_diag_ops = { + .owner = THIS_MODULE, + .open = himax_diag_proc_open, + .read = seq_read, + .write = himax_diag_write, +}; +#endif + +#ifdef HX_TP_PROC_RESET +static ssize_t himax_reset_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[12]; + + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + return -EFAULT; + + /*if (buf_tmp[0] == '1') + ESD_HW_REST();*/ + + return len; +} + +const struct file_operations himax_proc_reset_ops = { + .owner = THIS_MODULE, + .write = himax_reset_write, +}; +#endif + +#ifdef HX_TP_PROC_DEBUG +static ssize_t himax_debug_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (debug_level_cmd == 't') { + if (fw_update_complete) { + count += snprintf(temp_buf, len, + "FW Update Complete "); + } else { + count += snprintf(temp_buf, len, + "FW Update Fail "); + } + + } else if (debug_level_cmd == 'h') { + if (handshaking_result == 0) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (MCU Running)\n", + handshaking_result); + } else if (handshaking_result == 1) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (MCU Stop)\n", + handshaking_result); + } else if (handshaking_result == 2) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (I2C Error)\n", + handshaking_result); + } else { + count += snprintf(temp_buf, len, + "Handshaking Result = error\n"); + } + } else if (debug_level_cmd == 'v') { + count += snprintf(temp_buf + count, len, + "FW_VER = "); + count += snprintf(temp_buf + count, len, + "0x%2.2X\n", ic_data->vendor_fw_ver); + count += snprintf(temp_buf + count, len, + "CONFIG_VER = "); + count += snprintf(temp_buf + count, len, + "0x%2.2X\n", ic_data->vendor_config_ver); + count += snprintf(temp_buf + count, len, + "\n"); + } else if (debug_level_cmd == 'd') { + count += snprintf(temp_buf + count, len, + "Himax Touch IC Information :\n"); + if (IC_TYPE == HX_85XX_D_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : D\n"); + } else if (IC_TYPE == HX_85XX_E_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : E\n"); + } else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : ES\n"); + } else if (IC_TYPE == HX_85XX_F_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : F\n"); + } else { + count += snprintf(temp_buf + count, len, + "IC Type error.\n"); + } + if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) { + count += snprintf(temp_buf + count, len, + "IC Checksum : SW\n"); + } else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) { + count += snprintf(temp_buf + count, len, + "IC Checksum : HW\n"); + } else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) { + count += snprintf(temp_buf + count, len, + "IC Checksum : CRC\n"); + } else { + count += snprintf(temp_buf + count, len, + "IC Checksum error.\n"); + } + if (ic_data->HX_INT_IS_EDGE) { + count += snprintf(temp_buf + count, len, + "Interrupt : EDGE TIRGGER\n"); + } else { + count += snprintf(temp_buf + count, len, + "Interrupt : LEVEL TRIGGER\n"); + } + count += snprintf(temp_buf + count, len, + "RX Num : %d\n", ic_data->HX_RX_NUM); + count += snprintf(temp_buf + count, len, + "TX Num : %d\n", ic_data->HX_TX_NUM); + count += snprintf(temp_buf + count, len, + "BT Num : %d\n", ic_data->HX_BT_NUM); + count += snprintf(temp_buf + count, len, + "X Resolution : %d\n", ic_data->HX_X_RES); + count += snprintf(temp_buf + count, len, + "Y Resolution : %d\n", ic_data->HX_Y_RES); + count += snprintf(temp_buf + count, len, + "Max Point : %d\n", ic_data->HX_MAX_PT); + count += snprintf(temp_buf + count, len, + "XY reverse : %d\n", ic_data->HX_XY_REVERSE); + #ifdef HX_TP_PROC_2T2R + if (Is_2T2R) { + count += snprintf(temp_buf + count, len, + "2T2R panel\n"); + count += snprintf(temp_buf + count, len, + "RX Num_2 : %d\n", HX_RX_NUM_2); + count += snprintf(temp_buf + count, len, + "TX Num_2 : %d\n", HX_TX_NUM_2); + } + #endif + } else if (debug_level_cmd == 'i') { + count += snprintf(temp_buf + count, len, + "Himax Touch Driver Version:\n"); + count += snprintf(temp_buf + count, len, + "%s\n", HIMAX_DRIVER_VER); + } + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + return count; +} + +static ssize_t himax_debug_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + int result = 0; + char fileName[128]; + char buf[80] = {0}; + const struct firmware *fw = NULL; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == 'h') {/*handshaking*/ + debug_level_cmd = buf[0]; + + himax_int_enable(private_ts->client->irq, 0); + + /*0:Running, 1:Stop, 2:I2C Fail*/ + handshaking_result = himax_hand_shaking(private_ts->client); + + himax_int_enable(private_ts->client->irq, 1); + + return len; + } else if (buf[0] == 'v') { /*firmware version*/ + debug_level_cmd = buf[0]; + himax_int_enable(private_ts->client->irq, 0); +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(false, false); +#endif + himax_read_FW_ver(private_ts->client); + /*himax_check_chip_version();*/ +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true, false); +#endif + himax_int_enable(private_ts->client->irq, 1); + return len; + } else if (buf[0] == 'd') { /*ic information*/ + + debug_level_cmd = buf[0]; + return len; + } else if (buf[0] == 'i') {/*driver version*/ + + debug_level_cmd = buf[0]; + return len; + } else if (buf[0] == 't') { + + himax_int_enable(private_ts->client->irq, 0); + debug_level_cmd = buf[0]; + fw_update_complete = false; + + result = himax_load_CRC_bin_file(private_ts->client); + if (result < 0) { + E("%s: himax_load_CRC_bin_file fail Error Code=%d.\n", + __func__, result); + return result; + } + + memset(fileName, 0, 128); +/* parse the file name*/ + snprintf(fileName, len-4, "%s", &buf[4]); + I("%s: upgrade from file(%s) start!\n", __func__, fileName); + result = request_firmware(&fw, fileName, private_ts->dev); + if (result < 0) { + I("fail to request_firmware fwpath: %s (ret:%d)\n", + fileName, result); + return result; + } + I("%s: FW image: %02X, %02X, %02X, %02X ret=%d\n", __func__, + fw->data[0], fw->data[1], fw->data[2], fw->data[3], result); + if (result >= 0) { + /*start to upgrade*/ + himax_int_enable(private_ts->client->irq, 0); + + if ((buf[1] == '6') && (buf[2] == '0')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_60k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + } else if ((buf[1] == '6') && (buf[2] == '4')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_64k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + } else if ((buf[1] == '2') && (buf[2] == '4')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_124k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + } else if ((buf[1] == '2') && (buf[2] == '8')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_128k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + } else { + E("%s: Flash command fail: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } + release_firmware(fw); + goto firmware_upgrade_done; + /*return count;*/ + } + } + +firmware_upgrade_done: + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true, false); +#endif + + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + himax_int_enable(private_ts->client->irq, 1); + + /*todo himax_chip->tp_firmware_upgrade_proceed = 0; + todo himax_chip->suspend_state = 0; + todo enable_irq(himax_chip->irq);*/ + return len; +} + +const struct file_operations himax_proc_debug_ops = { + .owner = THIS_MODULE, + .read = himax_debug_read, + .write = himax_debug_write, +}; + +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + +static uint8_t getFlashCommand(void) +{ + return flash_command; +} + +static uint8_t getFlashDumpProgress(void) +{ + return flash_progress; +} + +static uint8_t getFlashDumpComplete(void) +{ + return flash_dump_complete; +} + +static uint8_t getFlashDumpFail(void) +{ + return flash_dump_fail; +} + +uint8_t getSysOperation(void) +{ + return sys_operation; +} + +static uint8_t getFlashReadStep(void) +{ + return flash_read_step; +} +/* +static uint8_t getFlashDumpSector(void) +{ + return flash_dump_sector; +} + +static uint8_t getFlashDumpPage(void) +{ + return flash_dump_page; +} +*/ +bool getFlashDumpGoing(void) +{ + return flash_dump_going; +} + +void setFlashBuffer(void) +{ + flash_buffer = kzalloc + (Flash_Size * sizeof(uint8_t), GFP_KERNEL); + memset(flash_buffer, 0x00, Flash_Size); +} + +void setSysOperation(uint8_t operation) +{ + sys_operation = operation; +} + +static void setFlashDumpProgress(uint8_t progress) +{ + flash_progress = progress; + /*I("setFlashDumpProgress : progress = %d , + flash_progress = %d\n",progress,flash_progress);*/ +} + +static void setFlashDumpComplete(uint8_t status) +{ + flash_dump_complete = status; +} + +static void setFlashDumpFail(uint8_t fail) +{ + flash_dump_fail = fail; +} + +static void setFlashCommand(uint8_t command) +{ + flash_command = command; +} + +static void setFlashReadStep(uint8_t step) +{ + flash_read_step = step; +} + +static void setFlashDumpSector(uint8_t sector) +{ + flash_dump_sector = sector; +} + +static void setFlashDumpPage(uint8_t page) +{ + flash_dump_page = page; +} + +static void setFlashDumpGoing(bool going) +{ + flash_dump_going = going; +} + +static ssize_t himax_proc_flash_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + int loop_i; + uint8_t local_flash_read_step = 0; + uint8_t local_flash_complete = 0; + uint8_t local_flash_progress = 0; + uint8_t local_flash_command = 0; + uint8_t local_flash_fail = 0; + char *temp_buf; + + local_flash_complete = getFlashDumpComplete(); + local_flash_progress = getFlashDumpProgress(); + local_flash_command = getFlashCommand(); + local_flash_fail = getFlashDumpFail(); + + I("flash_progress = %d\n", local_flash_progress); + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (local_flash_fail) { + ret += snprintf(temp_buf + ret, len, + "FlashStart:Fail\n"); + ret += snprintf(temp_buf + ret, len, + "FlashEnd"); + ret += snprintf(temp_buf + ret, len, + "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (!local_flash_complete) { + ret += snprintf(temp_buf+ret, len, + "FlashStart:Ongoing:0x%2.2x\n", flash_progress); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (local_flash_command == 1 && local_flash_complete) { + ret += snprintf(temp_buf+ret, len, + "FlashStart:Complete\n"); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (local_flash_command == 3 && local_flash_complete) { + ret += snprintf(temp_buf+ret, len, "FlashStart:\n"); + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + ret += snprintf(temp_buf + ret, len, + "x%2.2x", flash_buffer[loop_i]); + if ((loop_i % 16) == 15) + ret += snprintf(temp_buf + ret, len, + "\n"); + } + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + /*flash command == 0 , report the data*/ + local_flash_read_step = getFlashReadStep(); + + ret += snprintf(temp_buf + ret, len, + "FlashStart:%2.2x\n", local_flash_read_step); + + for (loop_i = 0 ; loop_i < 1024 ; loop_i++) { + ret += snprintf(temp_buf + ret, len, "x%2.2X", + flash_buffer[local_flash_read_step * 1024 + loop_i]); + + if ((loop_i % 16) == 15) + ret += snprintf(temp_buf + ret, len, "\n"); + } + + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + return ret; +} + +static ssize_t himax_proc_flash_write(struct file *file, +const char *buff, size_t len, loff_t *pos) +{ + char buf_tmp[6]; + unsigned long result = 0; + uint8_t loop_i = 0; + int base = 0; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + + I("%s: buf[0] = %s\n", __func__, buf); + + if (getSysOperation() == 1) { + E("%s: PROC is busy , return!\n", __func__); + return len; + } + + if (buf[0] == '0') { + setFlashCommand(0); + if (buf[1] == ':' && buf[2] == 'x') { + memcpy(buf_tmp, buf + 3, 2); + I("%s: read_Step = %s\n", __func__, buf_tmp); + if (!kstrtoul(buf_tmp, 16, &result)) { + I("%s: read_Step = %lu\n", __func__, result); + setFlashReadStep(result); + } + } + /* 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k*/ + } else if (buf[0] == '1') { + + setSysOperation(1); + setFlashCommand(1); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + if ((buf[1] == '_') && (buf[2] == '6')) { + if (buf[3] == '0') + Flash_Size = FW_SIZE_60k; + else if (buf[3] == '4') + Flash_Size = FW_SIZE_64k; + + } else if ((buf[1] == '_') && (buf[2] == '2')) { + if (buf[3] == '4') + Flash_Size = FW_SIZE_124k; + else if (buf[3] == '8') + Flash_Size = FW_SIZE_128k; + } + queue_work(private_ts->flash_wq, &private_ts->flash_work); + /* 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k*/ + } else if (buf[0] == '2') { + setSysOperation(1); + setFlashCommand(2); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + if ((buf[1] == '_') && (buf[2] == '6')) { + if (buf[3] == '0') + Flash_Size = FW_SIZE_60k; + else if (buf[3] == '4') + Flash_Size = FW_SIZE_64k; + + } else if ((buf[1] == '_') && (buf[2] == '2')) { + if (buf[3] == '4') + Flash_Size = FW_SIZE_124k; + else if (buf[3] == '8') + Flash_Size = FW_SIZE_128k; + + } + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } else if (buf[0] == '3') { + setSysOperation(1); + setFlashCommand(3); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + + memcpy(buf_tmp, buf + 3, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + setFlashDumpSector(result); + + memcpy(buf_tmp, buf + 7, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + setFlashDumpPage(result); + + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } else if (buf[0] == '4') { + I("%s: command 4 enter.\n", __func__); + setSysOperation(1); + setFlashCommand(4); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + + memcpy(buf_tmp, buf + 3, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + setFlashDumpSector(result); + else + E("%s: command 4 , sector error.\n", __func__); + return len; + + + memcpy(buf_tmp, buf + 7, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + setFlashDumpPage(result); + else + E("%s: command 4 , page error.\n", __func__); + return len; + + base = 11; + + I("=========Himax flash page buffer start=========\n"); + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + memcpy(buf_tmp, buf + base, 2); + if (!kstrtoul(buf_tmp, 16, &result)) { + flash_buffer[loop_i] = result; + I("%d ", flash_buffer[loop_i]); + if (loop_i % 16 == 15) + I("\n"); + } + base += 3; + } + I("=========Himax flash page buffer end=========\n"); + + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + return len; +} + +const struct file_operations himax_proc_flash_ops = { + .owner = THIS_MODULE, + .read = himax_proc_flash_read, + .write = himax_proc_flash_write, +}; + +void himax_ts_flash_func(void) +{ + uint8_t local_flash_command = 0; + + himax_int_enable(private_ts->client->irq, 0); + setFlashDumpGoing(true); + + /*sector = getFlashDumpSector();*/ + /*page = getFlashDumpPage();*/ + + local_flash_command = getFlashCommand(); + + msleep(100); + + I("%s: local_flash_command = %d enter.\n", + __func__, local_flash_command); + + if ((local_flash_command == 1 || local_flash_command == 2) + || (local_flash_command == 0x0F)) { + himax_flash_dump_func(private_ts->client, + local_flash_command, Flash_Size, flash_buffer); + } + + + I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); + + if (local_flash_command == 2) { + struct file *fn; + struct filename *vts_name; + + vts_name = getname_kernel(FLASH_DUMP_FILE); + fn = file_open_name(vts_name, O_CREAT | O_WRONLY, 0); + if (!IS_ERR(fn)) { + I("%s create file and ready to write\n", __func__); + fn->f_op->write(fn, flash_buffer, + Flash_Size * sizeof(uint8_t), &fn->f_pos); + + filp_close(fn, NULL); + } + } + + himax_int_enable(private_ts->client->irq, 1); + setFlashDumpGoing(false); + + setFlashDumpComplete(1); + setSysOperation(0); + return; + +/* Flash_Dump_i2c_transfer_error: + + himax_int_enable(private_ts->client->irq, 1); + setFlashDumpGoing(false); + setFlashDumpComplete(0); + setFlashDumpFail(1); + setSysOperation(0); + return; +*/ +} + +#endif + +#ifdef HX_TP_PROC_SELF_TEST +static ssize_t himax_self_test_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int val = 0x00; + int ret = 0; + char *temp_buf; + + I("%s:enter, %d\n", __func__, __LINE__); + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + himax_int_enable(private_ts->client->irq, 0);/*disable irq*/ + val = himax_chip_self_test(private_ts->client); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + himax_int_enable(private_ts->client->irq, 1);/*enable irq*/ + + if (val == 0x01) { + ret += snprintf(temp_buf + ret, len, + "Self_Test Pass\n"); + } else { + ret += snprintf(temp_buf + ret, len, + "Self_Test Fail\n"); + } + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + return ret; +} + +/* +static ssize_t himax_chip_self_test_store(struct device *dev, +struct device_attribute *attr, const char *buf, size_t count) +{ + char buf_tmp[2]; + unsigned long result = 0; + + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + memcpy(buf_tmp, buf, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + sel_type = (uint8_t)result; + } + I("sel_type = %x \r\n", sel_type); + return count; +} +*/ + +const struct file_operations himax_proc_self_test_ops = { + .owner = THIS_MODULE, + .read = himax_self_test_read, +}; +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF +static ssize_t himax_sense_on_off_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0') { + himax_sense_off(private_ts->client); + I("Sense off\n"); + } else if (buf[0] == '1') { + if (buf[1] == '1') { + himax_sense_on(private_ts->client, 0x01); + I("Sense on re-map off, run flash\n"); + } else if (buf[1] == '0') { + himax_sense_on(private_ts->client, 0x00); + I("Sense on re-map on, run sram\n"); + } else { + I("Do nothing\n"); + } + } else { + I("Do nothing\n"); + } + return len; +} + +const struct file_operations himax_proc_sense_on_off_ops = { + .owner = THIS_MODULE, + .write = himax_sense_on_off_write, +}; +#endif + +#ifdef HX_HIGH_SENSE +static ssize_t himax_HSEN_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t count = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + count = snprintf(temp_buf, len, "%d\n", ts->HSEN_enable); + HX_PROC_SEND_FLAG = 1; + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + + kfree(temp_buf); + } else + HX_PROC_SEND_FLAG = 0; + return count; +} + +static ssize_t himax_HSEN_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0') + ts->HSEN_enable = 0; + else if (buf[0] == '1') + ts->HSEN_enable = 1; + else + return -EINVAL; + + himax_set_HSEN_func(ts->client, ts->HSEN_enable); + + I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable); + + return len; +} + +const struct file_operations himax_proc_HSEN_ops = { + .owner = THIS_MODULE, + .read = himax_HSEN_read, + .write = himax_HSEN_write, +}; +#endif + +#ifdef HX_SMART_WAKEUP +static ssize_t himax_SMWP_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + struct himax_ts_data *ts = private_ts; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + count = snprintf(temp_buf, "%d\n", len, ts->SMWP_enable); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + + return count; +} + +static ssize_t himax_SMWP_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0') + ts->SMWP_enable = 0; + else if (buf[0] == '1') + ts->SMWP_enable = 1; + else + return -EINVAL; + + himax_set_SMWP_func(ts->client, ts->SMWP_enable); + HX_SMWP_EN = ts->SMWP_enable; + I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN); + + return len; +} + +const struct file_operations himax_proc_SMWP_ops = { + .owner = THIS_MODULE, + .read = himax_SMWP_read, + .write = himax_SMWP_write, +}; + +static ssize_t himax_GESTURE_read(struct file *file, +char *buf, size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i = 0; + int ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + for (i = 0 ; i < 16 ; i++) + ret += snprintf(temp_buf + ret, len, + "ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]); + + HX_PROC_SEND_FLAG = 1; + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + HX_PROC_SEND_FLAG = 0; + ret = 0; + } + return ret; +} + +static ssize_t himax_GESTURE_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i = 0; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + I("himax_GESTURE_store= %s\n", buf); + for (i = 0 ; i < 16 ; i++) { + if (buf[i] == '0') + ts->gesture_cust_en[i] = 0; + else if (buf[i] == '1') + ts->gesture_cust_en[i] = 1; + else + ts->gesture_cust_en[i] = 0; + I("gesture en[%d]=%d\n", i, ts->gesture_cust_en[i]); + } + return len; +} + +const struct file_operations himax_proc_Gesture_ops = { + .owner = THIS_MODULE, + .read = himax_GESTURE_read, + .write = himax_GESTURE_write, +}; +#endif + +int himax_touch_proc_init(void) +{ + himax_touch_proc_dir = proc_mkdir(HIMAX_PROC_TOUCH_FOLDER, NULL); + if (himax_touch_proc_dir == NULL) { + E(" %s: himax_touch_proc_dir file create failed!\n", __func__); + return -ENOMEM; + } + + himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops); + + if (himax_proc_debug_level_file == NULL) { + E(" %s: proc debug_level file create failed!\n", __func__); + goto fail_1; + } + + himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_vendor_ops); + + if (himax_proc_vendor_file == NULL) { + E(" %s: proc vendor file create failed!\n", __func__); + goto fail_2; + } + + himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_attn_ops); + + if (himax_proc_attn_file == NULL) { + E(" %s: proc attn file create failed!\n", __func__); + goto fail_3; + } + + himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops); + + if (himax_proc_int_en_file == NULL) { + E(" %s: proc int en file create failed!\n", __func__); + goto fail_4; + } + + himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops); + + if (himax_proc_layout_file == NULL) { + E(" %s: proc layout file create failed!\n", __func__); + goto fail_5; + } + +#ifdef HX_TP_PROC_RESET + himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, + (S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops); + + if (himax_proc_reset_file == NULL) { + E(" %s: proc reset file create failed!\n", __func__); + goto fail_6; + } +#endif + +#ifdef HX_TP_PROC_DIAG + himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops); + + if (himax_proc_diag_file == NULL) { + E(" %s: proc diag file create failed!\n", __func__); + goto fail_7; + } + himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE, + (S_IWUSR | S_IRUGO), + himax_touch_proc_dir, &himax_proc_diag_arrange_ops); + + if (himax_proc_diag_arrange_file == NULL) { + E(" %s: proc diag file create failed!\n", __func__); + goto fail_7_1; + } +#endif + +#ifdef HX_TP_PROC_REGISTER + himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops); + + if (himax_proc_register_file == NULL) { + E(" %s: proc register file create failed!\n", __func__); + goto fail_8; + } +#endif + +#ifdef HX_TP_PROC_DEBUG + himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops); + + if (himax_proc_debug_file == NULL) { + E(" %s: proc debug file create failed!\n", __func__); + goto fail_9; + } +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops); + + if (himax_proc_flash_dump_file == NULL) { + E(" %s: proc flash dump file create failed!\n", __func__); + goto fail_10; + } +#endif + +#ifdef HX_TP_PROC_SELF_TEST + himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops); + + if (himax_proc_self_test_file == NULL) { + E(" %s: proc self_test file create failed!\n", __func__); + goto fail_11; + } +#endif + +#ifdef HX_HIGH_SENSE + himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_HSEN_ops); + + if (himax_proc_HSEN_file == NULL) { + E(" %s: proc HSEN file create failed!\n", __func__); + goto fail_12; + } +#endif + +#ifdef HX_SMART_WAKEUP + himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_SMWP_ops); + + if (himax_proc_SMWP_file == NULL) { + E(" %s: proc SMWP file create failed!\n", __func__); + goto fail_13; + } + + himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_Gesture_ops); + + if (himax_proc_GESTURE_file == NULL) { + E(" %s: proc GESTURE file create failed!\n", __func__); + goto fail_14; + } +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF + himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_sense_on_off_ops); + + if (himax_proc_SENSE_ON_OFF_file == NULL) { + E(" %s: proc SENSE_ON_OFF file create failed!\n", __func__); + goto fail_15; + } +#endif + + return 0; + +#ifdef HX_TP_PROC_SENSE_ON_OFF +fail_15: +#endif +#ifdef HX_SMART_WAKEUP + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); +fail_14: + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); +fail_13: +#endif +#ifdef HX_HIGH_SENSE + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); +fail_12: +#endif +#ifdef HX_TP_PROC_SELF_TEST + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); +fail_11: +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); +fail_10: +#endif +#ifdef HX_TP_PROC_DEBUG + remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); +fail_9: +#endif +#ifdef HX_TP_PROC_REGISTER + remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); +fail_8: +#endif +#ifdef HX_TP_PROC_DIAG + remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); +fail_7: + remove_proc_entry(HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir); +fail_7_1: +#endif +#ifdef HX_TP_PROC_RESET + remove_proc_entry(HIMAX_PROC_RESET_FILE, himax_touch_proc_dir); +fail_6: +#endif + remove_proc_entry(HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir); +fail_5: remove_proc_entry(HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir); +fail_4: remove_proc_entry(HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir); +fail_3: remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); +fail_2: remove_proc_entry(HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir); +fail_1: remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); + return -ENOMEM; +} + +void himax_touch_proc_deinit(void) +{ +#ifdef HX_TP_PROC_SENSE_ON_OFF + remove_proc_entry(HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_SMART_WAKEUP + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_DOT_VIEW + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_SELF_TEST + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_DEBUG + remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_REGISTER + remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_DIAG + remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_RESET + remove_proc_entry(HIMAX_PROC_RESET_FILE, himax_touch_proc_dir); +#endif + remove_proc_entry(HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); +} +#endif diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.h b/drivers/input/touchscreen/hxchipset/himax_debug.h new file mode 100644 index 000000000000..7a24a170eaca --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_debug.h @@ -0,0 +1,197 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + #define HIMAX_PROC_TOUCH_FOLDER "android_touch" + #define HIMAX_PROC_DEBUG_LEVEL_FILE "debug_level" + #define HIMAX_PROC_VENDOR_FILE "vendor" + #define HIMAX_PROC_ATTN_FILE "attn" + #define HIMAX_PROC_INT_EN_FILE "int_en" + #define HIMAX_PROC_LAYOUT_FILE "layout" + + static struct proc_dir_entry *himax_touch_proc_dir; + static struct proc_dir_entry *himax_proc_debug_level_file; + static struct proc_dir_entry *himax_proc_vendor_file; + static struct proc_dir_entry *himax_proc_attn_file; + static struct proc_dir_entry *himax_proc_int_en_file; + static struct proc_dir_entry *himax_proc_layout_file; + + uint8_t HX_PROC_SEND_FLAG; + + extern int himax_touch_proc_init(void); + extern void himax_touch_proc_deinit(void); + bool getFlashDumpGoing(void); + + extern struct himax_ic_data *ic_data; + extern struct himax_ts_data *private_ts; + extern unsigned char IC_TYPE; + extern unsigned char IC_CHECKSUM; + +#ifdef QCT + extern irqreturn_t himax_ts_thread(int irq, void *ptr); +#endif +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + extern irqreturn_t tpd_eint_interrupt_handler(int irq, void *desc); +#else + extern void tpd_eint_interrupt_handler(void); +#endif +#endif + +#ifdef HX_TP_PROC_REGISTER + #define HIMAX_PROC_REGISTER_FILE "register" + struct proc_dir_entry *himax_proc_register_file = NULL; + uint8_t register_command[4]; +#endif + +#ifdef HX_TP_PROC_DIAG + #define HIMAX_PROC_DIAG_FILE "diag" + struct proc_dir_entry *himax_proc_diag_file = NULL; + #define HIMAX_PROC_DIAG_ARR_FILE "diag_arr" + struct proc_dir_entry *himax_proc_diag_arrange_file = NULL; + +#ifdef HX_TP_PROC_2T2R + static bool Is_2T2R; + static uint8_t x_channel_2; + static uint8_t y_channel_2; + static uint8_t *diag_mutual_2; + + int16_t *getMutualBuffer_2(void); + uint8_t getXChannel_2(void); + uint8_t getYChannel_2(void); + + void setMutualBuffer_2(void); + void setXChannel_2(uint8_t x); + void setYChannel_2(uint8_t y); +#endif + uint8_t x_channel = 0; + uint8_t y_channel = 0; + int16_t *diag_mutual = NULL; + int16_t *diag_mutual_new = NULL; + int16_t *diag_mutual_old = NULL; + uint8_t diag_max_cnt = 0; + + int diag_command = 0; + uint8_t diag_coor[128];/* = {0xFF};*/ + int16_t diag_self[100] = {0}; + + int16_t *getMutualBuffer(void); + int16_t *getMutualNewBuffer(void); + int16_t *getMutualOldBuffer(void); + int16_t *getSelfBuffer(void); + uint8_t getDiagCommand(void); + uint8_t getXChannel(void); + uint8_t getYChannel(void); + + void setMutualBuffer(void); + void setMutualNewBuffer(void); + void setMutualOldBuffer(void); + void setXChannel(uint8_t x); + void setYChannel(uint8_t y); + uint8_t coordinate_dump_enable = 0; + struct file *coordinate_fn; +#endif + +#ifdef HX_TP_PROC_DEBUG + #define HIMAX_PROC_DEBUG_FILE "debug" + struct proc_dir_entry *himax_proc_debug_file = NULL; + + bool fw_update_complete = false; + int handshaking_result = 0; + unsigned char debug_level_cmd = 0; + unsigned char upgrade_fw[128*1024]; +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + #define HIMAX_PROC_FLASH_DUMP_FILE "flash_dump" + struct proc_dir_entry *himax_proc_flash_dump_file = NULL; + + static int Flash_Size = 131072; + static uint8_t *flash_buffer; + static uint8_t flash_command; + static uint8_t flash_read_step; + static uint8_t flash_progress; + static uint8_t flash_dump_complete; + static uint8_t flash_dump_fail; + static uint8_t sys_operation; + static uint8_t flash_dump_sector; + static uint8_t flash_dump_page; + static bool flash_dump_going; + + static uint8_t getFlashCommand(void); + static uint8_t getFlashDumpComplete(void); + static uint8_t getFlashDumpFail(void); + static uint8_t getFlashDumpProgress(void); + static uint8_t getFlashReadStep(void); + /*static uint8_t getFlashDumpSector(void);*/ + /*static uint8_t getFlashDumpPage(void);*/ + + void setFlashBuffer(void); + uint8_t getSysOperation(void); + + static void setFlashCommand(uint8_t command); + static void setFlashReadStep(uint8_t step); + static void setFlashDumpComplete(uint8_t complete); + static void setFlashDumpFail(uint8_t fail); + static void setFlashDumpProgress(uint8_t progress); + void setSysOperation(uint8_t operation); + static void setFlashDumpSector(uint8_t sector); + static void setFlashDumpPage(uint8_t page); + static void setFlashDumpGoing(bool going); + +#endif + +#ifdef HX_TP_PROC_SELF_TEST + #define HIMAX_PROC_SELF_TEST_FILE "self_test" + struct proc_dir_entry *himax_proc_self_test_file = NULL; + uint32_t **raw_data_array; + uint8_t X_NUM = 0, Y_NUM = 0; + uint8_t sel_type = 0x0D; +#endif + +#ifdef HX_TP_PROC_RESET +#define HIMAX_PROC_RESET_FILE "reset" +extern void himax_HW_reset(uint8_t loadconfig, uint8_t int_off); +struct proc_dir_entry *himax_proc_reset_file; +#endif + +#ifdef HX_HIGH_SENSE + #define HIMAX_PROC_HSEN_FILE "HSEN" + struct proc_dir_entry *himax_proc_HSEN_file = NULL; +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF + #define HIMAX_PROC_SENSE_ON_OFF_FILE "SenseOnOff" + struct proc_dir_entry *himax_proc_SENSE_ON_OFF_file = NULL; +#endif + +#ifdef HX_RST_PIN_FUNC + void himax_HW_reset(uint8_t loadconfig, uint8_t int_off); +#endif + +#ifdef HX_SMART_WAKEUP +#define HIMAX_PROC_SMWP_FILE "SMWP" +struct proc_dir_entry *himax_proc_SMWP_file; +#define HIMAX_PROC_GESTURE_FILE "GESTURE" +struct proc_dir_entry *himax_proc_GESTURE_file; +uint8_t HX_SMWP_EN; +/*extern bool FAKE_POWER_KEY_SEND;*/ +#endif + +#endif + diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.c b/drivers/input/touchscreen/hxchipset/himax_ic.c new file mode 100644 index 000000000000..e2934c2d2396 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic.c @@ -0,0 +1,2381 @@ +/* Himax Android Driver Sample Code for HMX83100 chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_ic.h" + +const struct firmware *i_TP_CRC_FW_128K; +const struct firmware *i_TP_CRC_FW_64K; +const struct firmware *i_TP_CRC_FW_124K; +const struct firmware *i_TP_CRC_FW_60K; + +unsigned long FW_VER_MAJ_FLASH_ADDR; +unsigned long FW_VER_MAJ_FLASH_LENG; +unsigned long FW_VER_MIN_FLASH_ADDR; +unsigned long FW_VER_MIN_FLASH_LENG; +unsigned long CFG_VER_MAJ_FLASH_ADDR; +unsigned long CFG_VER_MAJ_FLASH_LENG; +unsigned long CFG_VER_MIN_FLASH_ADDR; +unsigned long CFG_VER_MIN_FLASH_LENG; + +unsigned char IC_TYPE; +unsigned char IC_CHECKSUM; + + /*0:Running, 1:Stop, 2:I2C Fail*/ +int himax_hand_shaking(struct i2c_client *client) +{ + int ret, result; + uint8_t hw_reset_check[1]; + uint8_t hw_reset_check_2[1]; + uint8_t buf0[2]; + uint8_t IC_STATUS_CHECK = 0xAA; + + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); + memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2)); + + buf0[0] = 0xF2; + if (IC_STATUS_CHECK == 0xAA) { + buf0[1] = 0xAA; + IC_STATUS_CHECK = 0x55; + } else { + buf0[1] = 0x55; + IC_STATUS_CHECK = 0xAA; + } + + ret = i2c_himax_master_write(client, + buf0, 2, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:write 0xF2 failed line: %d\n", __LINE__); + goto work_func_send_i2c_msg_fail; + } + msleep(50); + + buf0[0] = 0xF2; + buf0[1] = 0x00; + ret = i2c_himax_master_write(client, + buf0, 2, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:write 0x92 failed line: %d\n", __LINE__); + goto work_func_send_i2c_msg_fail; + } + usleep_range(1999, 2000); + + ret = i2c_himax_read(client, 0xD1, + hw_reset_check, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:i2c_himax_read 0xD1 failed line: %d\n", __LINE__); + goto work_func_send_i2c_msg_fail; + } + + if (IC_STATUS_CHECK != hw_reset_check[0]) { + usleep_range(1999, 2000); + ret = i2c_himax_read(client, 0xD1, + hw_reset_check_2, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:i2c_himax_read 0xD1 failed line: %d\n", + __LINE__); + goto work_func_send_i2c_msg_fail; + } + + if (hw_reset_check[0] == hw_reset_check_2[0]) + result = 1; + else + result = 0; + + } else { + result = 0; + } + + return result; + +work_func_send_i2c_msg_fail: + return 2; +} + +void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + if (diag_command != 0) + diag_command = diag_command + 5; + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0x80; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = diag_command; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} + +void himax_flash_dump_func(struct i2c_client *client, +uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer) +{ + /*struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, flash_work);*/ + /*uint8_t sector = 0;*/ + /*uint8_t page = 0;*/ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t out_buffer[20]; + uint8_t in_buffer[260]; + int page_prog_start = 0; + int i = 0; + + himax_sense_off(client); + himax_burst_enable(client, 0); + /*=============Dump Flash Start=============*/ + /*=====================================*/ + /* SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780*/ + /*=====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + for (page_prog_start = 0 ; page_prog_start < Flash_Size; + page_prog_start = page_prog_start + 256) { + /*===================================== + SPI Transfer Control + Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + Set read start address : 0x8000_0028 ==> 0x0000_0000 + Set command : 0x8000_0024 ==> 0x0000_003B + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; + tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + AHB_I2C Burst Read + Set SPI data register : 0x8000_002C ==> 0x00 + =====================================*/ + out_buffer[0] = 0x2C; + out_buffer[1] = 0x00; + out_buffer[2] = 0x00; + out_buffer[3] = 0x80; + i2c_himax_write(client, 0x00, out_buffer, 4, 3); + + /*===================================== + Read access : 0x0C ==> 0x00 + =====================================*/ + out_buffer[0] = 0x00; + i2c_himax_write(client, 0x0C, out_buffer, 1, 3); + + /*===================================== + Read 128 bytes two times + =====================================*/ + i2c_himax_read(client, 0x08, in_buffer, 128, 3); + for (i = 0 ; i < 128 ; i++) + flash_buffer[i + page_prog_start] + = in_buffer[i]; + + i2c_himax_read(client, 0x08 , in_buffer, 128, 3); + for (i = 0 ; i < 128 ; i++) + flash_buffer[(i + 128) + page_prog_start] + = in_buffer[i]; + + I("%s:Verify Progress: %x\n", __func__, page_prog_start); + } + +/*=============Dump Flash End=============*/ + /*//msleep(100); + for( i=0 ; i<8 ;i++) + { + for(j=0 ; j<64 ; j++) + { + setFlashDumpProgress(i*32 + j); + } + } + */ + himax_sense_on(client, 0x01); + + return; + +} + +int himax_chip_self_test(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + int pf_value = 0x00; + uint8_t test_result_id = 0; + int j; + + memset(tmp_addr, 0x00, sizeof(tmp_addr)); + memset(tmp_data, 0x00, sizeof(tmp_data)); + + himax_interface_on(client); + himax_sense_off(client); + + /*Set criteria*/ + himax_burst_enable(client, 1); + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; + tmp_data[3] = 0x14; tmp_data[2] = 0xC8; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_data[7] = 0x13; tmp_data[6] = 0x60; + tmp_data[5] = 0x0A; tmp_data[4] = 0x99; + + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 8); + + /*start selftest*/ + /* 0x9008_805C ==> 0x0000_0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + himax_sense_on(client, 1); + + msleep(2000); + + himax_sense_off(client); + msleep(20); + + /*===================================== + Read test result ID : 0x9008_8078 ==> 0xA/0xB/0xC/0xF + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x78; + himax_register_read(client, tmp_addr, 1, tmp_data); + + test_result_id = tmp_data[0]; + + I("%s: check test result, test_result_id=%x, test_result=%x\n", + __func__ , test_result_id, tmp_data[0]); + + if (test_result_id == 0xF) { + I("[Himax]: self-test pass\n"); + pf_value = 0x1; + } else { + E("[Himax]: self-test fail\n"); + pf_value = 0x0; + } + himax_burst_enable(client, 1); + + for (j = 0 ; j < 10 ; j++) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x06; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x0C; + himax_register_read(client, tmp_addr, 1, tmp_data); + I("[Himax]: 9006000C = %d\n", tmp_data[0]); + if (tmp_data[0] != 0) { + tmp_data[3] = 0x90; tmp_data[2] = 0x06; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x00, + tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + i2c_himax_read(client, 0x08, + tmp_data, 124, HIMAX_I2C_RETRY_TIMES); + } else { + break; + } + } + + himax_sense_on(client, 1); + msleep(120); + + return pf_value; +} + +void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = HSEN_enable; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} +void himax_get_HSEN_enable(struct i2c_client *client, uint8_t *tmp_data) +{ + uint8_t tmp_addr[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + himax_register_read(client, tmp_addr, 1, tmp_data); +} + +void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} + +void himax_get_SMWP_enable(struct i2c_client *client, +uint8_t *tmp_data) +{ + uint8_t tmp_addr[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + himax_register_read(client, tmp_addr, 1, tmp_data); +} + +int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte) +{ + uint8_t tmp_data[4]; + int err = -1; + + tmp_data[0] = 0x31; + + if (i2c_himax_write(client, 0x13, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return err; + } + + tmp_data[0] = (0x10 | auto_add_4_byte); + if (i2c_himax_write(client, 0x0D, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return err; + } + return 0; + +} + +void himax_register_read(struct i2c_client *client, +uint8_t *read_addr, int read_length, uint8_t *read_data) +{ + uint8_t tmp_data[4]; + int i = 0; + int address = 0; + + if (read_length > 256) { + E("%s: read len over 256!\n", __func__); + return; + } + if (read_length > 1) + himax_burst_enable(client, 1); + else + himax_burst_enable(client, 0); + + address = (read_addr[3] << 24) + + (read_addr[2] << 16) + + (read_addr[1] << 8) + + read_addr[0]; + + i = address; + tmp_data[0] = (uint8_t)i; + tmp_data[1] = (uint8_t)(i >> 8); + tmp_data[2] = (uint8_t)(i >> 16); + tmp_data[3] = (uint8_t)(i >> 24); + if (i2c_himax_write(client, 0x00, + tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + if (i2c_himax_read(client, 0x08, + read_data, read_length * 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + if (read_length > 1) + himax_burst_enable(client, 0); +} + +void himax_flash_read(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *read_data) +{ + uint8_t tmpbyte[2]; + + if (i2c_himax_write(client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(client, 0x03, + ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + tmpbyte[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_read(client, 0x08, + &read_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_read(client, 0x09, + &read_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_read(client, 0x0A, + &read_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_read(client, 0x0B, + &read_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_read(client, 0x18, + &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } /* No bus request*/ + + if (i2c_himax_read(client, 0x0F, + &tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } /* idle state*/ + +} + +void himax_flash_write_burst(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *write_data) +{ + uint8_t data_byte[8]; + int i = 0, j = 0; + + for (i = 0 ; i < 4; i++) + data_byte[i] = reg_byte[i]; + + for (j = 4 ; j < 8; j++) + data_byte[j] = write_data[j-4]; + + if (i2c_himax_write(client, 0x00, + data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + +} + +int himax_flash_write_burst_length(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *write_data, int length) +{ + uint8_t data_byte[256]; + int i = 0, j = 0, err = -1; + + for (i = 0 ; i < 4 ; i++) + data_byte[i] = reg_byte[i]; + + for (j = 4 ; j < length + 4 ; j++) + data_byte[j] = write_data[j - 4]; + + if (i2c_himax_write(client, 0x00, + data_byte, length + 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return err; + } + return 0; +} + +int himax_register_write(struct i2c_client *client, +uint8_t *write_addr, int write_length, uint8_t *write_data) +{ + int i = 0, address = 0; + int ret = 0, err = -1; + + address = (write_addr[3] << 24) + + (write_addr[2] << 16) + + (write_addr[1] << 8) + + write_addr[0]; + + for (i = address ; i < address + write_length * 4; + i = i + 4) { + if (write_length > 1) { + ret = himax_burst_enable(client, 1); + if (ret) + return err; + } else { + ret = himax_burst_enable(client, 0); + if (ret) + return err; + } + ret = himax_flash_write_burst_length(client, + write_addr, write_data, write_length * 4); + if (ret < 0) + return err; + } + + return 0; +} + +void himax_sense_off(struct i2c_client *client) +{ + uint8_t wdt_off = 0x00; + uint8_t tmp_addr[4]; + uint8_t tmp_data[5]; + + himax_burst_enable(client, 0); + + while (wdt_off == 0x00) { + /* 0x9000_800C ==> 0x0000_AC53*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0xAC; tmp_data[0] = 0x53; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*=====================================*/ + /* Read Watch Dog disable password : + 0x9000_800C ==> 0x0000_AC53 */ + /*=====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + himax_register_read(client, tmp_addr, 1, tmp_data); + + /*Check WDT*/ + if (tmp_data[0] == 0x53 && tmp_data[1] == 0xAC + && tmp_data[2] == 0x00 && tmp_data[3] == 0x00) + wdt_off = 0x01; + else + wdt_off = 0x00; + } + + /* VCOM //0x9008_806C ==> 0x0000_0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x6C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(20); + + /* 0x9000_0010 ==> 0x0000_00DA*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xDA; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Read CPU clock off password : 0x9000_0010 ==> 0x0000_00DA + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + himax_register_read(client, tmp_addr, 1, tmp_data); + I("%s: CPU clock off password data[0]=%x", + __func__, tmp_data[0]); + I(" data[1]=%x data[2]=%x data[3]=%x\n", + tmp_data[1], tmp_data[2], tmp_data[3]); + +} + +void himax_interface_on(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[5]; + + /*===================================== + Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000 + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + himax_flash_read(client, tmp_addr, tmp_data); /*avoid RD/WR fail*/ +} + +bool wait_wip(struct i2c_client *client, int Timing) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t in_buffer[10]; + /*uint8_t out_buffer[20];*/ + int retry_cnt = 0; + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + in_buffer[0] = 0x01; + + do { + /*===================================== + SPI Transfer Control : 0x8000_0020 ==> 0x4200_0003 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x42; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x03; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + SPI Command : 0x8000_0024 ==> 0x0000_0005 + read 0x8000_002C for 0x01, means wait success + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x05; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + in_buffer[0] = in_buffer[1] = + in_buffer[2] = in_buffer[3] = 0xFF; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(client, tmp_addr, 1, in_buffer); + + if ((in_buffer[0] & 0x01) == 0x00) + return true; + + retry_cnt++; + + if (in_buffer[0] != 0x00 || in_buffer[1] != 0x00 + || in_buffer[2] != 0x00 || in_buffer[3] != 0x00){ + I("%s:Wait wip retry_cnt:%d, buffer[0]=%d, ", + __func__, retry_cnt, in_buffer[0]); + I("buffer[1]=%d, buffer[2]=%d, buffer[3]=%d\n", + in_buffer[1], in_buffer[2], in_buffer[3]); + } + if (retry_cnt > 100) { + E("%s: Wait wip error!\n", __func__); + return false; + } + msleep(Timing); + } while ((in_buffer[0] & 0x01) == 0x01); + return true; +} + +void himax_sense_on(struct i2c_client *client, uint8_t FlashMode) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + + himax_interface_on(client); + himax_burst_enable(client, 0); + /*CPU reset*/ + /* 0x9000_0014 ==> 0x0000_00CA*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xCA; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Read pull low CPU reset signal : 0x9000_0014 ==> 0x0000_00CA + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + himax_register_read(client, tmp_addr, 1, tmp_data); + + I("%s: check pull low CPU reset signal data[0]=%x data[1]=%x ", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); + + /* 0x9000_0014 ==> 0x0000_0000*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Read revert pull low CPU reset signal : 0x9000_0014 ==> 0x0000_0000 + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + himax_register_read(client, tmp_addr, 1, tmp_data); + + I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x ", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); + + /*===================================== + Reset TCON + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + usleep_range(9999, 10000); + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + if (FlashMode == 0x00) { /*SRAM*/ + /*===================================== + Re-map + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xF1; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); + I("%s:83100_Chip_Re-map ON\n", __func__); + } else { + /*===================================== + Re-map off + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); + I("%s:83100_Chip_Re-map OFF\n", __func__); + } + /*===================================== + CPU clock on + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); + +} + +void himax_chip_erase(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Chip Erase + Erase Command : 0x8000_0024 ==> 0x0000_00C7 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xC7; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(2000); + + if (!wait_wip(client, 100)) + E("%s:83100_Chip_Erase Fail\n", __func__); + +} + +bool himax_block_erase(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Block Erase + Erase Command : + 0x8000_0028 ==> 0x0000_0000 //SPI addr + 0x8000_0020 ==> 0x6700_0000 //control + 0x8000_0024 ==> 0x0000_0052 //BE + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x52; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(1000); + + if (!wait_wip(client, 100)) { + E("%s:83100_Erase Fail\n", __func__); + return false; + } else { + return true; + } + +} + +bool himax_sector_erase(struct i2c_client *client, int start_addr) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int page_prog_start = 0; + + himax_burst_enable(client, 0); + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + for (page_prog_start = start_addr; + page_prog_start < start_addr + 0x0F000; + page_prog_start = page_prog_start + 0x1000) { + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Sector Erase + Erase Command : + 0x8000_0028 ==> 0x0000_0000 //SPI addr + 0x8000_0020 ==> 0x6700_0000 //control + 0x8000_0024 ==> 0x0000_0020 //SE + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x20; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(200); + + if (!wait_wip(client, 100)) { + E("%s:83100_Erase Fail\n", __func__); + return false; + } + } + return true; +} + +void himax_sram_write(struct i2c_client *client, uint8_t *FW_content) +{ + int i = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[64]; + int FW_length = 0x4000; /* 0x4000 = 16K bin file */ + + /*himax_sense_off(client);*/ + + for (i = 0; i < FW_length; i = i + 64) { + himax_burst_enable(client, 1); + + if (i < 0x100) { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = i; + } else if (i >= 0x100 && i < 0x10000) { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = (i >> 8); + tmp_addr[0] = i; + } + + memcpy(&tmp_data[0], &FW_content[i], 64); + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 64); + + } + + if (!wait_wip(client, 100)) + E("%s:83100_Sram_Write Fail\n", __func__); +} + +bool himax_sram_verify(struct i2c_client *client, +uint8_t *FW_File, int FW_Size) +{ + int i = 0; + uint8_t out_buffer[20]; + uint8_t in_buffer[128]; + uint8_t *get_fw_content; + + get_fw_content = kzalloc(0x4000 * sizeof(uint8_t), GFP_KERNEL); + + for (i = 0 ; i < 0x4000 ; i = i + 128) { + himax_burst_enable(client, 1); + + /*===================================== + AHB_I2C Burst Read + =====================================*/ + if (i < 0x100) { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = 0x00; + out_buffer[0] = i; + } else if (i >= 0x100 && i < 0x10000) { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = (i >> 8); + out_buffer[0] = i; + } + + if (i2c_himax_write(client, 0x00, out_buffer, + 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + out_buffer[0] = 0x00; + if (i2c_himax_write(client, 0x0C, out_buffer, + 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + if (i2c_himax_read(client, 0x08, in_buffer, + 128, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + memcpy(&get_fw_content[i], &in_buffer[0], 128); + } + + for (i = 0 ; i < FW_Size ; i++) { + if (FW_File[i] != get_fw_content[i]) { + E("%s: fail! SRAM[%x]=%x NOT CRC_ifile=%x\n", + __func__, i, get_fw_content[i], FW_File[i]); + return false; + } + } + + kfree(get_fw_content); + + return true; +} + +void himax_flash_programming(struct i2c_client *client, +uint8_t *FW_content, int FW_Size) +{ + int page_prog_start = 0; + int program_length = 48; + int i = 0, j = 0, k = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + /* // Read for flash data, 128K //4 bytes for 0x80002C padding */ + uint8_t buring_data[256]; + + /*himax_interface_on(client);*/ + himax_burst_enable(client, 0); + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + for (page_prog_start = 0 ; page_prog_start < FW_Size; + page_prog_start = page_prog_start + 256) { + /*msleep(5);*/ + /*===================================== + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + SPI Transfer Control + Set 256 bytes page write : 0x8000_0020 ==> 0x610F_F000 + Set read start address : 0x8000_0028 ==> 0x0000_0000 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x61; tmp_data[2] = 0x0F; + tmp_data[1] = 0xF0; tmp_data[0] = 0x00; + /*data bytes should be 0x6100_0000 + + ((word_number)*4-1)*4096 = 0x6100_0000 + + 0xFF000 = 0x610F_F000 + Programmable size = 1 page = 256 bytes, + word_number = 256 byte / 4 = 64*/ + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + /* tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + // Flash start address 1st : 0x0000_0000 */ + + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Send 16 bytes data : 0x8000_002C ==> 16 bytes data + =====================================*/ + buring_data[0] = 0x2C; + buring_data[1] = 0x00; + buring_data[2] = 0x00; + buring_data[3] = 0x80; + + for (i = /*0*/page_prog_start, j = 0; + i < 16 + page_prog_start/**/; + i++, j++) { /* <------ bin file*/ + + buring_data[j + 4] = FW_content[i]; + } + + if (i2c_himax_write(client, 0x00, buring_data, + 20, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + /*===================================== + Write command : 0x8000_0024 ==> 0x0000_0002 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x02; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Send 240 bytes data : 0x8000_002C ==> 240 bytes data + =====================================*/ + + for (j = 0; j < 5; j++) { + for (i = (page_prog_start + 16 + (j * 48)), k = 0; + i < (page_prog_start + 16 + (j * 48)) + program_length; + i++, k++) { /*<------ bin file*/ + buring_data[k+4] = FW_content[i];/*(byte)i;*/ + } + + if (i2c_himax_write(client, 0x00, buring_data, + program_length + 4, + HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + } + + if (!wait_wip(client, 1)) + E("%s:83100_Flash_Programming Fail\n", __func__); + } +} + +bool himax_check_chip_version(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t ret_data = 0x00; + int i = 0; + int ret = 0; + + himax_sense_off(client); + + for (i = 0 ; i < 5 ; i++) { + /* 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) */ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + ret = himax_register_write(client, tmp_addr, 1, tmp_data); + if (ret) + return false; + + /* 2. Set bank as 0 (0x8001_BD01 = 0x0000_0000)*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xBD; tmp_addr[0] = 0x01; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + ret = himax_register_write(client, tmp_addr, 1, tmp_data); + if (ret) + return false; + + /* 3. Read driver ID register RF4H 1 byte (0x8001_F401) + // Driver register RF4H 1 byte value = 0x84H, + read back value will become 0x84848484 */ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xF4; tmp_addr[0] = 0x01; + himax_register_read(client, tmp_addr, 1, tmp_data); + ret_data = tmp_data[0]; + + I("%s:Read driver IC ID = %X\n", __func__, ret_data); + if (ret_data == 0x84) { + IC_TYPE = HX_83100_SERIES_PWON; + /*himax_sense_on(client, 0x01);*/ + ret_data = true; + break; + + } else { + ret_data = false; + E("%s:Read driver ID register Fail:\n", __func__); + } + } + /* 4. After read finish, set DDREG_Req = 0 + (0x9000_0020 = 0x0000_0000) (Unlock register R/W from driver)*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_register_write(client, tmp_addr, 1, tmp_data); + /*himax_sense_on(client, 0x01);*/ + return ret_data; +} + +/*#if 1*/ +int himax_check_CRC(struct i2c_client *client, int mode) +{ + bool burnFW_success = false; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int tmp_value; + int CRC_value = 0; + + memset(tmp_data, 0x00, sizeof(tmp_data)); + if (i_TP_CRC_FW_60K == NULL) { + I("%s: i_TP_CRC_FW_60K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_64K == NULL) { + I("%s: i_TP_CRC_FW_64K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_124K == NULL) { + I("%s: i_TP_CRC_FW_124K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_128K == NULL) { + I("%s: i_TP_CRC_FW_128K = NULL\n", __func__); + return 0; + } + + if (1) { + if (mode == fw_image_60k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_60K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_60K->data, 0x4000); + } else if (mode == fw_image_64k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_64K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_64K->data, 0x4000); + } else if (mode == fw_image_124k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_124K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_124K->data, 0x4000); + } else if (mode == fw_image_128k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_128K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_128K->data, 0x4000); + } + if (burnFW_success) { + I("%s: Start to do CRC FW mode=%d\n", __func__, mode); + himax_sense_on(client, 0x00); /* run CRC firmware*/ + + while (true) { + msleep(100); + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; + tmp_addr[0] = 0x94; + himax_register_read(client, + tmp_addr, 1, tmp_data); + + I("%s: CRC from firmware is %x, %x, %x, %x\n", + __func__, tmp_data[3], tmp_data[2], + tmp_data[1], tmp_data[0]); +/* + if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF + && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF) { + } else + break; + */ + if (!(tmp_data[3] == 0xFF + && tmp_data[2] == 0xFF + && tmp_data[1] == 0xFF + && tmp_data[0] == 0xFF)) { + break; + } + } + + CRC_value = tmp_data[3]; + + tmp_value = tmp_data[2] << 8; + CRC_value += tmp_value; + + tmp_value = tmp_data[1] << 16; + CRC_value += tmp_value; + + tmp_value = tmp_data[0] << 24; + CRC_value += tmp_value; + + I("%s: CRC Value is %x\n", __func__, CRC_value); + + /*Close Remapping*/ + /*===================================== + Re-map close + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, + tmp_addr, tmp_data, 4); + return CRC_value; + + } else { + E("%s: SRAM write fail\n", __func__); + return 0; + } + } else + I("%s: NO CRC Check File\n", __func__); + + return 0; +} + +bool Calculate_CRC_with_AP(unsigned char *FW_content, +int CRC_from_FW, int mode) +{ + uint8_t tmp_data[4]; + int i, j; + int fw_data; + int fw_data_2; + int CRC = 0xFFFFFFFF; + int PolyNomial = 0x82F63B78; + int length = 0; + + if (mode == fw_image_128k) + length = 0x8000; + else if (mode == fw_image_124k) + length = 0x7C00; + else if (mode == fw_image_64k) + length = 0x4000; + else /*if (mode == fw_image_60k)*/ + length = 0x3C00; + + for (i = 0 ; i < length ; i++) { + fw_data = FW_content[i * 4]; + + for (j = 1 ; j < 4 ; j++) { + fw_data_2 = FW_content[i * 4 + j]; + fw_data += (fw_data_2) << (8 * j); + } + + CRC = fw_data ^ CRC; + + for (j = 0 ; j < 32 ; j++) { + if ((CRC % 2) != 0) + CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; + else + CRC = (((CRC >> 1) ^ 0x7FFFFFFF) & 0x7FFFFFFF); + } + } + + I("%s: CRC calculate from bin file is %x\n", __func__, CRC); + + tmp_data[0] = (uint8_t)(CRC >> 24); + tmp_data[1] = (uint8_t)(CRC >> 16); + tmp_data[2] = (uint8_t)(CRC >> 8); + tmp_data[3] = (uint8_t) CRC; + + CRC = tmp_data[0]; + CRC += tmp_data[1] << 8; + CRC += tmp_data[2] << 16; + CRC += tmp_data[3] << 24; + + I("%s: CRC calculate from bin file REVERSE %x\n", __func__, CRC); + I("%s: CRC calculate from FWis %x\n", __func__, CRC_from_FW); + if (CRC_from_FW == CRC) + return true; + else + return false; +} +/*#endif*/ + +int himax_load_CRC_bin_file(struct i2c_client *client) +{ + int err = 0; + char *CRC_60_firmware_name = "HX_CRC_60.bin"; + char *CRC_64_firmware_name = "HX_CRC_64.bin"; + char *CRC_124_firmware_name = "HX_CRC_124.bin"; + char *CRC_128_firmware_name = "HX_CRC_128.bin"; + + I("%s,Entering\n", __func__); + if (i_TP_CRC_FW_60K == NULL) { + I("load file name = %s\n", CRC_60_firmware_name); + err = request_firmware(&i_TP_CRC_FW_60K, + CRC_60_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -1; + goto request_60k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_60K\n", __func__); + + if (i_TP_CRC_FW_64K == NULL) { + I("load file name = %s\n", CRC_64_firmware_name); + err = request_firmware(&i_TP_CRC_FW_64K, + CRC_64_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -2; + goto request_64k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_64K\n", __func__); + + if (i_TP_CRC_FW_124K == NULL) { + I("load file name = %s\n", CRC_124_firmware_name); + err = request_firmware(&i_TP_CRC_FW_124K, + CRC_124_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -3; + goto request_124k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_124K\n", __func__); + + if (i_TP_CRC_FW_128K == NULL) { + I("load file name = %s\n", CRC_128_firmware_name); + err = request_firmware(&i_TP_CRC_FW_128K, + CRC_128_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -4; + goto request_128k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_128K\n", __func__); + + return err; + +request_128k_fw_fail: + release_firmware(i_TP_CRC_FW_124K); +request_124k_fw_fail: + release_firmware(i_TP_CRC_FW_64K); +request_64k_fw_fail: + release_firmware(i_TP_CRC_FW_60K); +request_60k_fw_fail: + return err; +} +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x10000) {/*64k*/ + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + if (!himax_sector_erase(client, 0x00000)) { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } + himax_flash_programming(client, fw, 0x0F000); + + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ + + CRC_from_FW = himax_check_CRC(client, fw_image_60k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_60k); + /*himax_sense_on(client, 0x01);*/ + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x10000) { /*64k*/ + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + himax_chip_erase(client); + himax_flash_programming(client, fw, len); + + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ + + CRC_from_FW = himax_check_CRC(client, fw_image_64k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_64k); + /*himax_sense_on(client, 0x01);*/ + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x20000) { /*128k*/ + E("%s: The file size is not 128K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + if (!himax_block_erase(client)) { + E("%s:Block erase fail!Please restart the IC.\n", __func__); + return false; + } + if (!himax_sector_erase(client, 0x10000)) { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } + himax_flash_programming(client, fw, 0x1F000); + + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ + + CRC_from_FW = himax_check_CRC(client, fw_image_124k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_124k); + /*himax_sense_on(client, 0x01);*/ + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x20000) { /*128k*/ + E("%s: The file size is not 128K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + himax_chip_erase(client); + + himax_flash_programming(client, fw, len); + + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ + + CRC_from_FW = himax_check_CRC(client, fw_image_128k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_128k); + /*himax_sense_on(client, 0x01); */ + return burnFW_success; +} + +void himax_touch_information(struct i2c_client *client) +{ + uint8_t cmd[4]; + char data[12] = {0}; + + I("%s:IC_TYPE =%d\n", __func__, IC_TYPE); + + if (IC_TYPE == HX_83100_SERIES_PWON) { + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xF8; + himax_register_read(client, cmd, 1, data); + + ic_data->HX_RX_NUM = data[1]; + ic_data->HX_TX_NUM = data[2]; + ic_data->HX_MAX_PT = data[3]; + + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xFC; + himax_register_read(client, cmd, 1, data); + + if ((data[1] & 0x04) == 0x04) + ic_data->HX_XY_REVERSE = true; + else + ic_data->HX_XY_REVERSE = false; + + ic_data->HX_Y_RES = data[3]*256; + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x01; cmd[0] = 0x00; + himax_register_read(client, cmd, 1, data); + ic_data->HX_Y_RES = ic_data->HX_Y_RES + data[0]; + ic_data->HX_X_RES = data[1]*256 + data[2]; + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x8C; + himax_register_read(client, cmd, 1, data); + if ((data[0] & 0x01) == 1) + ic_data->HX_INT_IS_EDGE = true; + else + ic_data->HX_INT_IS_EDGE = false; + + if (ic_data->HX_RX_NUM > 40) + ic_data->HX_RX_NUM = 29; + if (ic_data->HX_TX_NUM > 20) + ic_data->HX_TX_NUM = 16; + if (ic_data->HX_MAX_PT > 10) + ic_data->HX_MAX_PT = 10; + if (ic_data->HX_Y_RES > 2000) + ic_data->HX_Y_RES = 1280; + if (ic_data->HX_X_RES > 2000) + ic_data->HX_X_RES = 720; +#ifdef HX_EN_MUT_BUTTON + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xE8; + himax_register_read(client, cmd, 1, data); + ic_data->HX_BT_NUM = data[3]; +#endif + I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d\n", + __func__, ic_data->HX_RX_NUM, + ic_data->HX_TX_NUM, ic_data->HX_MAX_PT); + I("%s:HX_XY_REVERSE =%d,HX_Y_RES =%d,HX_X_RES=%d\n", + __func__, ic_data->HX_XY_REVERSE, + ic_data->HX_Y_RES, ic_data->HX_X_RES); + I("%s:HX_INT_IS_EDGE =%d\n", + __func__, ic_data->HX_INT_IS_EDGE); + } else { + ic_data->HX_RX_NUM = 0; + ic_data->HX_TX_NUM = 0; + ic_data->HX_BT_NUM = 0; + ic_data->HX_X_RES = 0; + ic_data->HX_Y_RES = 0; + ic_data->HX_MAX_PT = 0; + ic_data->HX_XY_REVERSE = false; + ic_data->HX_INT_IS_EDGE = false; + } +} + +void himax_read_FW_ver(struct i2c_client *client) +{ + uint8_t cmd[4]; + uint8_t data[64]; + + /*===================================== + Read FW version : 0x0000_E303 + =====================================*/ + cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x00; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_config_ver = data[3] << 8; + + cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x04; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_config_ver = data[0] | ic_data->vendor_config_ver; + I("CFG_VER : %X\n", ic_data->vendor_config_ver); + + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x28; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_fw_ver = data[0]<<8 | data[1]; + I("FW_VER : %X\n", ic_data->vendor_fw_ver); + +} + +bool himax_ic_package_check(struct i2c_client *client) +{ +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH + uint8_t cmd[3]; + uint8_t data[3]; + + memset(cmd, 0x00, sizeof(cmd)); + memset(data, 0x00, sizeof(data)); + + if (i2c_himax_read(client, 0xD1, cmd, 3, HIMAX_I2C_RETRY_TIMES) < 0) + return false; + + if (i2c_himax_read(client, 0x31, data, 3, HIMAX_I2C_RETRY_TIMES) < 0) + return false; + + if ((data[0] == 0x85 && data[1] == 0x29)) { + IC_TYPE = HX_85XX_F_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 64901; /*0xFD85*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 64902; /*0xFD86*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 64928; /*0xFDA0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 64940; /*0xFDAC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x F\n"); + } + if ((data[0] == 0x85 && data[1] == 0x30) + || (cmd[0] == 0x05 && cmd[1] == 0x85 && cmd[2] == 0x29)) { + IC_TYPE = HX_85XX_E_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /*0x00AC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x E\n"); + } else if ((data[0] == 0x85 && data[1] == 0x31)) { + IC_TYPE = HX_85XX_ES_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /*0x00AC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x ES\n"); + } else if ((data[0] == 0x85 && data[1] == 0x28) + || (cmd[0] == 0x04 && cmd[1] == 0x85 + && (cmd[2] == 0x26 || cmd[2] == 0x27 + || cmd[2] == 0x28))) { + IC_TYPE = HX_85XX_D_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /* 0x00AC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x D\n"); + } else if ((data[0] == 0x85 && data[1] == 0x23) || + (cmd[0] == 0x03 && cmd[1] == 0x85 && + (cmd[2] == 0x26 || cmd[2] == 0x27 || + cmd[2] == 0x28 || cmd[2] == 0x29))) { + IC_TYPE = HX_85XX_C_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 135; /*0x0087*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 147; /*0x0093*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x C\n"); + } else if ((data[0] == 0x85 && data[1] == 0x26) || + (cmd[0] == 0x02 && cmd[1] == 0x85 && + (cmd[2] == 0x19 || cmd[2] == 0x25 || cmd[2] == 0x26))) { + IC_TYPE = HX_85XX_B_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 728; /*0x02D8*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 692; /*0x02B4*/ + CFG_VER_MAJ_FLASH_LENG = 3; + CFG_VER_MIN_FLASH_ADDR = 704; /*0x02C0*/ + CFG_VER_MIN_FLASH_LENG = 3; + I("Himax IC package 852x B\n"); + } else if ((data[0] == 0x85 && data[1] == 0x20) || (cmd[0] == 0x01 && + cmd[1] == 0x85 && cmd[2] == 0x19)) { + IC_TYPE = HX_85XX_A_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + I("Himax IC package 852x A\n"); + } else { + E("Himax IC package incorrect!!\n"); + } +#else + IC_TYPE = HX_83100_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 57384; /*0xE028*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 57385; /*0xE029*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 58115; /*0xE303*/ + CFG_VER_MAJ_FLASH_LENG = 1; + CFG_VER_MIN_FLASH_ADDR = 58116; /*0xE304*/ + CFG_VER_MIN_FLASH_LENG = 1; + I("Himax IC package 83100_in\n"); + +#endif + return true; +} + +void himax_read_event_stack(struct i2c_client *client, +uint8_t *buf, uint8_t length) +{ + uint8_t cmd[4]; + + cmd[3] = 0x90; cmd[2] = 0x06; + cmd[1] = 0x00; cmd[0] = 0x00; + if (i2c_himax_write(client, 0x00, + cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + + cmd[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + + i2c_himax_read(client, 0x08, + buf, length, HIMAX_I2C_RETRY_TIMES); +} + +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static void himax_83100_Flash_Write(uint8_t *reg_byte, uint8_t *write_data) +{ + uint8_t tmpbyte[2]; + + if (i2c_himax_write(private_ts->client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, + 0x03, ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, + 0x04, &write_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, + 0x05, &write_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, + 0x06, &write_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, + 0x07, &write_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (isBusrtOn == false) { + tmpbyte[0] = 0x01; + if (i2c_himax_write(private_ts->client, + 0x0C, &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + } +} +#endif +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static void himax_83100_Flash_Burst_Write +(uint8_t *reg_byte, uint8_t *write_data) +{ + /*uint8_t tmpbyte[2];*/ + int i = 0; + + if (i2c_himax_write(private_ts->client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x03, + ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + /*Write 256 bytes with continue burst mode*/ + for (i = 0 ; i < 256 ; i = i + 4) { + if (i2c_himax_write(private_ts->client, + 0x04, &write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x05, + &write_data[i+1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x06, + &write_data[i+2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x07, + &write_data[i+3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + } + + /*if (isBusrtOn == false) + { + tmpbyte[0] = 0x01; + if (i2c_himax_write(private_ts->client, + 0x0C, &tmpbyte[0], 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + }*/ + +} +#endif + +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t out_buffer[20]; + uint8_t in_buffer[260]; + + int fail_addr = 0, fail_cnt = 0; + int page_prog_start = 0; + int i = 0; + + himax_interface_on(private_ts->client); + himax_burst_enable(private_ts->client, 0); + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + for (page_prog_start = 0; page_prog_start < FW_Size; + page_prog_start = page_prog_start + 256) { + /*===================================== + SPI Transfer Control + Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + Set read start address : 0x8000_0028 ==> 0x0000_0000 + Set command : 0x8000_0024 ==> 0x0000_003B + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; + tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_83100_Flash_Write(tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + /*================================== + AHB_I2C Burst Read + Set SPI data register : 0x8000_002C ==> 0x00 + ==================================*/ + out_buffer[0] = 0x2C; + out_buffer[1] = 0x00; + out_buffer[2] = 0x00; + out_buffer[3] = 0x80; + i2c_himax_write(private_ts->client, 0x00, + out_buffer, 4, HIMAX_I2C_RETRY_TIMES); + + /*================================== + Read access : 0x0C ==> 0x00 + ==================================*/ + out_buffer[0] = 0x00; + i2c_himax_write(private_ts->client, 0x0C, + out_buffer, 1, HIMAX_I2C_RETRY_TIMES); + + /*================================== + Read 128 bytes two times + ==================================*/ + i2c_himax_read(private_ts->client, 0x08, + in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + for (i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + + i2c_himax_read(private_ts->client, 0x08, + in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + for (i = 0; i < 128; i++) + flash_buffer[(i + 128) + + page_prog_start] = in_buffer[i]; + + /*tmp_addr[3] = 0x80; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(tmp_addr, 32, out in_buffer); + for (int i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(tmp_addr, 32, out in_buffer); + for (int i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + */ + I("%s:Verify Progress: %x\n", __func__, page_prog_start); + } + + fail_cnt = 0; + for (i = 0; i < FW_Size; i++) { + if (FW_File[i] != flash_buffer[i]) { + if (fail_cnt == 0) + fail_addr = i; + + fail_cnt++; + /*E("%s Fail Block:%x\n", __func__, i); + return false;*/ + } + } + if (fail_cnt > 0) { + E("%s:Start Fail Block:%x and fail block count=%x\n", + __func__, fail_addr, fail_cnt); + return false; + } + + I("%s:Byte read verify pass.\n", __func__); + return true; + +} +#endif + +void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data) +{ + int i; + int cnt = 0; + unsigned char tmp_addr[4]; + unsigned char tmp_data[4]; + uint8_t max_i2c_size = 32; + int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; + int total_size_4bytes = total_size / 4; + int total_read_times = 0; + unsigned long address = 0x08000468; + + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x5A; tmp_data[0] = 0xA5; + himax_flash_write_burst(client, tmp_addr, tmp_data); + do { + cnt++; + himax_register_read(client, tmp_addr, 1, tmp_data); + usleep_range(9999, 10000); + } while ((tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A) && cnt < 100); + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x68; + if (total_size_4bytes % max_i2c_size == 0) + total_read_times = total_size_4bytes / max_i2c_size; + else + total_read_times = total_size_4bytes / max_i2c_size + 1; + + for (i = 0 ; i < (total_read_times) ; i++) { + if (total_size_4bytes >= max_i2c_size) { + himax_register_read(client, tmp_addr, + max_i2c_size, + &info_data[i*max_i2c_size*4]); + total_size_4bytes = total_size_4bytes - max_i2c_size; + } else { + himax_register_read(client, tmp_addr, + total_size_4bytes % max_i2c_size, + &info_data[i*max_i2c_size*4]); + } + address += max_i2c_size * 4; + tmp_addr[1] = (uint8_t)((address>>8) & 0x00FF); + tmp_addr[0] = (uint8_t)((address) & 0x00FF); + } + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x11; tmp_data[2] = 0x22; + tmp_data[1] = 0x33; tmp_data[0] = 0x44; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} +/*ts_work*/ +int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max) +{ + int RawDataLen; + + if (raw_cnt_rmd != 0x00) + RawDataLen = 124 - ((HX_MAX_PT + raw_cnt_max + 3) * 4) - 1; + else + RawDataLen = 124 - ((HX_MAX_PT + raw_cnt_max + 2) * 4) - 1; + + return RawDataLen; +} + +bool read_event_stack(struct i2c_client *client, uint8_t *buf, int length) +{ + uint8_t cmd[4]; + + if (length > 56) + length = 124; + /*===================== + AHB I2C Burst Read + =====================*/ + cmd[0] = 0x31; + if (i2c_himax_write(client, 0x13, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + + cmd[0] = 0x10; + if (i2c_himax_write(client, 0x0D, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + /*===================== + Read event stack + =====================*/ + cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; + if (i2c_himax_write(client, 0x00, cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + + cmd[0] = 0x00; + if (i2c_himax_write(client, 0x0C, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + i2c_himax_read(client, 0x08, buf, length, HIMAX_I2C_RETRY_TIMES); + return 1; + +err_workqueue_out: + return 0; +} + +bool post_read_event_stack(struct i2c_client *client) +{ + return 1; +} +bool diag_check_sum(uint8_t hx_touch_info_size, +uint8_t *buf) /*return checksum value*/ +{ + uint16_t check_sum_cal = 0; + int i; + + /*Check 124th byte CRC*/ + for (i = hx_touch_info_size, check_sum_cal = 0 ; i < 124 ; i = i + 2) + check_sum_cal += (buf[i + 1] * 256 + buf[i]); + + if (check_sum_cal % 0x10000 != 0) { + I("%s:diag chksum fail!check_sum_cal=%X,hx_touchinfo_sz=%d,\n", + __func__, check_sum_cal, hx_touch_info_size); + return 0; + } + return 1; +} + +void diag_parse_raw_data(int hx_touch_info_size, +int RawDataLen, int mul_num, int self_num, uint8_t *buf, +uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data) +{ + int RawDataLen_word; + int index = 0; + int temp1, temp2, i; + + if (buf[hx_touch_info_size] == 0x3A && + buf[hx_touch_info_size + 1] == 0xA3 && + buf[hx_touch_info_size + 2] > 0 && + buf[hx_touch_info_size + 3] == diag_cmd + 5) { + RawDataLen_word = RawDataLen / 2; + index = (buf[hx_touch_info_size + 2] - 1) * RawDataLen_word; + /*I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", + index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num);*/ + for (i = 0; i < RawDataLen_word; i++) { + temp1 = index + i; + + if (temp1 < mul_num) { /*mutual*/ + /*4: RawData Header, 1:HSB */ + mutual_data[index + i] + = buf[i*2 + hx_touch_info_size + 4 + 1] + * 256 + + buf[i * 2 + hx_touch_info_size + 4]; + } else { /*self*/ + temp1 = i + index; + temp2 = self_num + mul_num; + + if (temp1 >= temp2) + break; + + /*4: RawData Header*/ + self_data[i + index - mul_num] + = buf[i * 2 + hx_touch_info_size + 4]; + self_data[i + index - mul_num + 1] + = buf[i * 2 + hx_touch_info_size + 4 + 1]; + } + } + } else { + I("[HIMAX TP MSG]%s: header format is wrong!\n", __func__); + I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", + index, buf[56], buf[57], buf[58], buf[59], + mul_num, self_num); + } +} diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.h b/drivers/input/touchscreen/hxchipset/himax_ic.h new file mode 100644 index 000000000000..ce7d0d49c362 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic.h @@ -0,0 +1,148 @@ +/* Himax Android Driver Sample Code for HMX83100 chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +#include + +#define HX_85XX_A_SERIES_PWON 1 +#define HX_85XX_B_SERIES_PWON 2 +#define HX_85XX_C_SERIES_PWON 3 +#define HX_85XX_D_SERIES_PWON 4 +#define HX_85XX_E_SERIES_PWON 5 +#define HX_85XX_ES_SERIES_PWON 6 +#define HX_85XX_F_SERIES_PWON 7 +#define HX_83100_SERIES_PWON 8 + +#define HX_TP_BIN_CHECKSUM_SW 1 +#define HX_TP_BIN_CHECKSUM_HW 2 +#define HX_TP_BIN_CHECKSUM_CRC 3 + +enum fw_image_type { + fw_image_60k = 0x01, + fw_image_64k, + fw_image_124k, + fw_image_128k, +}; + +int himax_hand_shaking(struct i2c_client *client); +void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable); +void himax_get_SMWP_enable(struct i2c_client *client, uint8_t *tmp_data); +void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable); +void himax_get_HSEN_enable(struct i2c_client *client, uint8_t *tmp_data); +void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command); + +void himax_flash_dump_func(struct i2c_client *client, +uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer); + +int himax_chip_self_test(struct i2c_client *client); + +/*himax_83100_BURST_INC0_EN*/ +int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte); + +/*RegisterRead83100*/ +void himax_register_read(struct i2c_client *client, + uint8_t *read_addr, int read_length, uint8_t *read_data); + +/*himax_83100_Flash_Read*/ +void himax_flash_read(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *read_data); + +/*himax_83100_Flash_Write_Burst*/ +void himax_flash_write_burst(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *write_data); + +/*himax_83100_Flash_Write_Burst_length*/ +int himax_flash_write_burst_length(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *write_data, int length); + +/*RegisterWrite83100*/ +int himax_register_write(struct i2c_client *client, + uint8_t *write_addr, int write_length, uint8_t *write_data); + +/*himax_83100_SenseOff*/ +void himax_sense_off(struct i2c_client *client); +/*himax_83100_Interface_on*/ +void himax_interface_on(struct i2c_client *client); +bool wait_wip(struct i2c_client *client, int Timing); + +/*himax_83100_SenseOn*/ +void himax_sense_on(struct i2c_client *client, + uint8_t FlashMode); + +/*himax_83100_Chip_Erase*/ +void himax_chip_erase(struct i2c_client *client); +/*himax_83100_Block_Erase*/ +bool himax_block_erase(struct i2c_client *client); + +/*himax_83100_Sector_Erase*/ +bool himax_sector_erase(struct i2c_client *client, int start_addr); + +/*himax_83100_Sram_Write*/ +void himax_sram_write(struct i2c_client *client, uint8_t *FW_content); + +/*himax_83100_Sram_Verify*/ +bool himax_sram_verify(struct i2c_client *client, + uint8_t *FW_File, int FW_Size); + +/*himax_83100_Flash_Programming*/ +void himax_flash_programming(struct i2c_client *client, + uint8_t *FW_content, int FW_Size); + +/*himax_83100_CheckChipVersion*/ +bool himax_check_chip_version(struct i2c_client *client); + +/*himax_83100_Check_CRC*/ +int himax_check_CRC(struct i2c_client *client, int mode); + +bool Calculate_CRC_with_AP(unsigned char *FW_content, + int CRC_from_FW, int mode); + +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +void himax_touch_information(struct i2c_client *client); +void himax_read_FW_ver(struct i2c_client *client); +bool himax_ic_package_check(struct i2c_client *client); + +void himax_read_event_stack(struct i2c_client *client, + uint8_t *buf, uint8_t length); + +int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max); +bool read_event_stack(struct i2c_client *client, uint8_t *buf_ts, int length); +bool post_read_event_stack(struct i2c_client *client); + +/*return checksum value*/ +bool diag_check_sum(uint8_t hx_touch_info_size, uint8_t *buf_ts); + +void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, + int mul_num, int self_num, uint8_t *buf_ts, + uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data); + +void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data); +extern struct himax_ts_data *private_ts; +extern struct himax_ic_data *ic_data; + +int himax_load_CRC_bin_file(struct i2c_client *client); diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c new file mode 100644 index 000000000000..309bb5e01073 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -0,0 +1,783 @@ +/* Himax Android Driver Sample Code for HIMAX chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) pr_info("[HXTP][DEBUG] " x) +#define I(x...) pr_info("[HXTP][INFO] " x) +#define W(x...) pr_info("[HXTP][WARNING] " x) +#define E(x...) pr_info("[HXTP][ERROR] " x) +#endif + +int irq_enable_count = 0; +#ifdef HX_SMART_WAKEUP +#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) +#endif + +#define PINCTRL_STATE_ACTIVE "pmx_ts_active" +#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" +#define PINCTRL_STATE_RELEASE "pmx_ts_release" + +/*extern int himax_ts_init(struct himax_ts_data *ts);*/ + +void himax_vk_parser(struct device_node *dt, + struct himax_i2c_platform_data *pdata) +{ + u32 data = 0; + uint8_t cnt = 0, i = 0; + uint32_t coords[4] = {0}; + struct device_node *node, *pp = NULL; + struct himax_virtual_key *vk; + + node = of_parse_phandle(dt, "virtualkey", 0); + if (node == NULL) { + I(" DT-No vk info in DT"); + return; + + } else { + while ((pp = of_get_next_child(node, pp))) + cnt++; + if (!cnt) + return; + + vk = kcalloc(cnt, sizeof(*vk), GFP_KERNEL); + pp = NULL; + while ((pp = of_get_next_child(node, pp))) { + if (of_property_read_u32(pp, "idx", &data) == 0) + vk[i].index = data; + if (of_property_read_u32_array(pp, "range", + coords, 4) == 0) { + vk[i].x_range_min = coords[0], + vk[i].x_range_max = coords[1]; + vk[i].y_range_min = coords[2], + vk[i].y_range_max = coords[3]; + } else + I(" range faile"); + i++; + } + pdata->virtual_key = vk; + for (i = 0; i < cnt; i++) + I(" vk[%d] idx:%d x_min:%d, y_max:%d", + i, pdata->virtual_key[i].index, + pdata->virtual_key[i].x_range_min, + pdata->virtual_key[i].y_range_max); + } +} + +int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata) +{ + int rc, coords_size = 0; + uint32_t coords[4] = {0}; + struct property *prop; + struct device_node *dt = ts->client->dev.of_node; + u32 data = 0; + + prop = of_find_property(dt, "himax,panel-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid panel coords size %d", + __func__, coords_size); + } + + if (of_property_read_u32_array(dt, "himax,panel-coords", + coords, coords_size) == 0) { + pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1]; + pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3]; + I(" DT-%s:panel-coords = %d, %d, %d, %d\n", + __func__, pdata->abs_x_min, pdata->abs_x_max, + pdata->abs_y_min, pdata->abs_y_max); + } + + prop = of_find_property(dt, "himax,display-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid display coords size %d", + __func__, coords_size); + } + rc = of_property_read_u32_array(dt, "himax,display-coords", + coords, coords_size); + if (rc && (rc != -EINVAL)) { + D(" %s:Fail to read display-coords %d\n", + __func__, rc); + return rc; + } + pdata->screenWidth = coords[1]; + pdata->screenHeight = coords[3]; + I(" DT-%s:display-coords = (%d, %d)", __func__, pdata->screenWidth, + pdata->screenHeight); + + pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); + if (!gpio_is_valid(pdata->gpio_irq)) + I(" DT:gpio_irq value is not valid\n"); + + pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); + if (!gpio_is_valid(pdata->gpio_reset)) + I(" DT:gpio_rst value is not valid\n"); + + pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); + if (!gpio_is_valid(pdata->gpio_3v3_en)) + I(" DT:gpio_3v3_en value is not valid\n"); + + I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", + pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); + + if (of_property_read_u32(dt, "report_type", &data) == 0) { + pdata->protocol_type = data; + I(" DT:protocol_type=%d", pdata->protocol_type); + } + + himax_vk_parser(dt, pdata); + + return 0; +} + +int i2c_himax_read(struct i2c_client *client, +uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &command, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + } + }; + mutex_lock(&private_ts->rw_lock); + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 2) == 2) + break; + msleep(20); + } + if (retry == toRetry) { + E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); + return -EIO; + } + mutex_unlock(&private_ts->rw_lock); + return 0; + +} + +int i2c_himax_write(struct i2c_client *client, +uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry/*, loop_i*/; + uint8_t buf[length + 1]; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length + 1, + .buf = buf, + } + }; + + buf[0] = command; + memcpy(buf+1, data, length); + mutex_lock(&private_ts->rw_lock); + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + + if (retry == toRetry) { + E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); + return -EIO; + } + mutex_unlock(&private_ts->rw_lock); + return 0; + +} + +int i2c_himax_read_command(struct i2c_client *client, +uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry) +{ + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + } + }; + mutex_lock(&private_ts->rw_lock); + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + if (retry == toRetry) { + E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); + return -EIO; + } + mutex_unlock(&private_ts->rw_lock); + return 0; +} + +int i2c_himax_write_command(struct i2c_client *client, +uint8_t command, uint8_t toRetry) +{ + return i2c_himax_write(client, command, NULL, 0, toRetry); +} + +int i2c_himax_master_write(struct i2c_client *client, +uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry/*, loop_i*/; + uint8_t buf[length]; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length, + .buf = buf, + } + }; + + memcpy(buf, data, length); + mutex_lock(&private_ts->rw_lock); + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + + if (retry == toRetry) { + E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); + return -EIO; + } + mutex_unlock(&private_ts->rw_lock); + return 0; +} + +void himax_int_enable(int irqnum, int enable) +{ + if (enable == 1 && irq_enable_count == 0) { + enable_irq(irqnum); + irq_enable_count++; + } else if (enable == 0 && irq_enable_count == 1) { + disable_irq_nosync(irqnum); + irq_enable_count--; + } + I("irq_enable_count = %d", irq_enable_count); +} + +void himax_rst_gpio_set(int pinnum, uint8_t value) +{ + gpio_direction_output(pinnum, value); +} + +uint8_t himax_int_gpio_read(int pinnum) +{ + return gpio_get_value(pinnum); +} + +#if defined(CONFIG_HMX_DB) +static int himax_regulator_configure(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) +{ + int retval; + + pdata->vcc_dig = regulator_get(&client->dev, "vdd"); + if (IS_ERR(pdata->vcc_dig)) { + E("%s: Failed to get regulator vdd\n", __func__); + retval = PTR_ERR(pdata->vcc_dig); + return retval; + } + pdata->vcc_ana = regulator_get(&client->dev, "avdd"); + if (IS_ERR(pdata->vcc_ana)) { + E("%s: Failed to get regulator avdd\n", __func__); + retval = PTR_ERR(pdata->vcc_ana); + regulator_put(pdata->vcc_ana); + return retval; + } + + return 0; +}; + +static int himax_power_on(struct himax_i2c_platform_data *pdata, +bool on) +{ + int retval; + + if (on) { + retval = regulator_enable(pdata->vcc_dig); + if (retval) { + E("%s: Failed to enable regulator vdd\n", __func__); + return retval; + } + msleep(100); + retval = regulator_enable(pdata->vcc_ana); + if (retval) { + E("%s: Failed to enable regulator avdd\n", __func__); + regulator_disable(pdata->vcc_dig); + return retval; + } + } else { + regulator_disable(pdata->vcc_dig); + regulator_disable(pdata->vcc_ana); + } + return 0; +} + +int himax_ts_pinctrl_init(struct himax_ts_data *ts) +{ + int retval; + + /* Get pinctrl if target uses pinctrl */ + ts->ts_pinctrl = devm_pinctrl_get(&(ts->client->dev)); + if (IS_ERR_OR_NULL(ts->ts_pinctrl)) { + retval = PTR_ERR(ts->ts_pinctrl); + dev_dbg(&ts->client->dev, "Target does not use pinctrl %d\n", + retval); + goto err_pinctrl_get; + } + + ts->pinctrl_state_active = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_ACTIVE); + if (IS_ERR_OR_NULL(ts->pinctrl_state_active)) { + retval = PTR_ERR(ts->pinctrl_state_active); + dev_err(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + + ts->pinctrl_state_suspend = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_SUSPEND); + if (IS_ERR_OR_NULL(ts->pinctrl_state_suspend)) { + retval = PTR_ERR(ts->pinctrl_state_suspend); + dev_err(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_SUSPEND, retval); + goto err_pinctrl_lookup; + } + + ts->pinctrl_state_release = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_RELEASE); + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + retval = PTR_ERR(ts->pinctrl_state_release); + dev_dbg(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_RELEASE, retval); + } + + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(ts->ts_pinctrl); +err_pinctrl_get: + ts->ts_pinctrl = NULL; + return retval; +} + +int himax_gpio_power_config(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) +{ + int error; + + error = himax_regulator_configure(client, pdata); + if (error) { + E("Failed to initialize hardware\n"); + goto err_regulator_not_on; + } + +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) { + /* configure touchscreen reset out gpio */ + error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); + if (error) { + E("unable to request gpio [%d]\n", + pdata->gpio_reset); + goto err_regulator_on; + } + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_req; + } + } +#endif + + error = himax_power_on(pdata, true); + if (error) { + E("Failed to power on hardware\n"); + goto err_gpio_reset_req; + } +#ifdef HX_IRQ_PIN_FUNC + /* configure touchscreen irq gpio */ + if (gpio_is_valid(pdata->gpio_irq)) { + error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_irq); + goto err_power_on; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + goto err_gpio_irq_req; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + goto err_power_on; + } +#endif + msleep(20); + +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_irq_req; + } + } +#endif + return 0; +#ifdef HX_RST_PIN_FUNC +err_gpio_irq_req: +#endif +#ifdef HX_IRQ_PIN_FUNC + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); +err_power_on: +#endif + himax_power_on(pdata, false); +err_gpio_reset_req: +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); +err_regulator_on: +#endif +err_regulator_not_on: + + return error; +} + +#else +int himax_gpio_power_config(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) +{ + int error = 0; + +#ifdef HX_RST_PIN_FUNC + if (pdata->gpio_reset >= 0) { + error = gpio_request(pdata->gpio_reset, "himax-reset"); + if (error < 0) { + E("%s: request reset pin failed\n", __func__); + return error; + } + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } +#endif + if (pdata->gpio_3v3_en >= 0) { + error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); + if (error < 0) { + E("%s: request 3v3_en pin failed\n", __func__); + return error; + } + gpio_direction_output(pdata->gpio_3v3_en, 1); + I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en)); + } + +#ifdef HX_IRQ_PIN_FUNC + if (gpio_is_valid(pdata->gpio_irq)) { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_irq); + return error; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + return error; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + return error; + } +#endif + + msleep(20); + +#ifdef HX_RST_PIN_FUNC + if (pdata->gpio_reset >= 0) { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } + msleep(20); +#endif + + return error; +} +#endif + +static void himax_ts_isr_func(struct himax_ts_data *ts) +{ + himax_ts_work(ts); +} + +irqreturn_t himax_ts_thread(int irq, void *ptr) +{ + uint8_t diag_cmd; + struct himax_ts_data *ts = ptr; + struct timespec timeStart, timeEnd, timeDelta; + + diag_cmd = getDiagCommand(); + + if (ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeStart); + usleep_range(4999, 5000); + /*I(" Irq start time = %ld.%06ld s\n", + timeStart.tv_sec, timeStart.tv_nsec/1000);*/ + } + +#ifdef HX_SMART_WAKEUP + if (atomic_read(&ts->suspend_mode) + && (!FAKE_POWER_KEY_SEND) + && (ts->SMWP_enable) + && (!diag_cmd)) { + __pm_wakeup_event(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); + msleep(200); + himax_wake_check_func(); + return IRQ_HANDLED; + } +#endif + himax_ts_isr_func((struct himax_ts_data *)ptr); + if (ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeEnd); + timeDelta.tv_nsec + = (timeEnd.tv_sec * 1000000000 + timeEnd.tv_nsec) + - (timeStart.tv_sec * 1000000000 + timeStart.tv_nsec); + /*I("Irq finish time = %ld.%06ld s\n", + timeEnd.tv_sec, timeEnd.tv_nsec/1000); + I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000);*/ + } + return IRQ_HANDLED; +} + +static void himax_ts_work_func(struct work_struct *work) +{ + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, work); + + himax_ts_work(ts); +} + +int tp_irq = -1; + +int himax_ts_register_interrupt(struct i2c_client *client) +{ + struct himax_ts_data *ts = i2c_get_clientdata(client); + int ret = 0; + + ts->irq_enabled = 0; + /*Work functon*/ + if (client->irq) {/*INT mode*/ + ts->use_irq = 1; + if (ic_data->HX_INT_IS_EDGE) { + I("%s edge triiger falling\n ", __func__); + ret = request_threaded_irq(client->irq, + NULL, himax_ts_thread, IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, client->name, ts); + } else { + I("%s level trigger low\n ", __func__); + ret = request_threaded_irq(client->irq, + NULL, himax_ts_thread, IRQF_TRIGGER_LOW + | IRQF_ONESHOT, client->name, ts); + } + if (ret == 0) { + ts->irq_enabled = 1; + irq_enable_count = 1; + tp_irq = client->irq; + I("%s: irq enabled at qpio: %d\n", + __func__, client->irq); +#ifdef HX_SMART_WAKEUP + irq_set_irq_wake(client->irq, 1); +#endif + } else { + ts->use_irq = 0; + E("%s: request_irq failed\n", __func__); + } + } else { + I("%s: client->irq is empty, use polling mode.\n", __func__); + } + /*if use polling mode need to disable HX_ESD_WORKAROUND function*/ + if (!ts->use_irq) { + ts->himax_wq = create_singlethread_workqueue("himax_touch"); + + INIT_WORK(&ts->work, himax_ts_work_func); + + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = himax_ts_timer_func; + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + I("%s: polling mode enabled\n", __func__); + } + return ret; +} + +static int himax_common_suspend(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter\n", __func__); + + himax_chip_common_suspend(ts); + return 0; +} + +static int himax_common_resume(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter\n", __func__); + + himax_chip_common_resume(ts); + return 0; +} + +#if defined(CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct himax_ts_data *ts + = container_of(self, struct himax_ts_data, fb_notif); + int ERR = 1; + + I(" %s\n", __func__); + if (evdata && evdata->data && event + == FB_EVENT_BLANK && ts && ts->client) { + blank = evdata->data; + + mutex_lock(&ts->fb_mutex); + switch (*blank) { + case FB_BLANK_UNBLANK: + if (!ts->probe_done) { + if (himax_ts_init(ts) == true) { + I("himax_ts_init return OK\n"); + ts->probe_done = true; + } else { + I("himax_ts_init return Fail\n"); + return -ERR; + } + } else + himax_common_resume(&ts->client->dev); + break; + + case FB_BLANK_POWERDOWN: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_NORMAL: + himax_common_suspend(&ts->client->dev); + break; + } + mutex_unlock(&ts->fb_mutex); + } + + return 0; +} +#endif + +static const struct i2c_device_id himax_common_ts_id[] = { + {HIMAX_common_NAME, 0 }, + {} +}; + +static const struct dev_pm_ops himax_common_pm_ops = { +#if (!defined(CONFIG_FB)) + .suspend = himax_common_suspend, + .resume = himax_common_resume, +#endif +}; + +#ifdef CONFIG_OF +static struct of_device_id himax_match_table[] = { + {.compatible = "himax,hxcommon" }, + {}, +}; +#else +#define himax_match_table NULL +#endif + +static struct i2c_driver himax_common_driver = { + .id_table = himax_common_ts_id, + .probe = himax_chip_common_probe, + .remove = himax_chip_common_remove, + .driver = { + .name = HIMAX_common_NAME, + .owner = THIS_MODULE, + .of_match_table = himax_match_table, +#ifdef CONFIG_PM + .pm = &himax_common_pm_ops, +#endif + }, +}; + +static int __init himax_common_init(void) +{ + I("Himax common touch panel driver init\n"); + i2c_add_driver(&himax_common_driver); + return 0; +} + +static void __exit himax_common_exit(void) +{ + i2c_del_driver(&himax_common_driver); +} + +module_init(himax_common_init); +module_exit(himax_common_exit); + +MODULE_DESCRIPTION("Himax_common driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h new file mode 100644 index 000000000000..6871e53cd1f2 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_platform.h @@ -0,0 +1,157 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef HIMAX_PLATFORM_H +#define HIMAX_PLATFORM_H + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_HMX_DB) +#include +#endif + +#define QCT + +#define HIMAX_I2C_RETRY_TIMES 10 + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) pr_info("[HXTP][DEBUG] " x) +#define I(x...) pr_info("[HXTP][INFO] " x) +#define W(x...) pr_info("[HXTP][WARNING] " x) +#define E(x...) pr_info("[HXTP][ERROR] " x) +#define DIF(x...) do { if (debug_flag) pr_info("[HXTP][DEBUG] " x) } while (0) +#else +#define D(x...) +#define I(x...) +#define W(x...) +#define E(x...) +#define DIF(x...) +#endif + +#if defined(CONFIG_HMX_DB) +/* Analog voltage @2.7 V */ +#define HX_VTG_MIN_UV 2700000 +#define HX_VTG_MAX_UV 3300000 +#define HX_ACTIVE_LOAD_UA 15000 +#define HX_LPM_LOAD_UA 10 +/* Digital voltage @1.8 V */ +#define HX_VTG_DIG_MIN_UV 1800000 +#define HX_VTG_DIG_MAX_UV 1800000 +#define HX_ACTIVE_LOAD_DIG_UA 10000 +#define HX_LPM_LOAD_DIG_UA 10 + +#define HX_I2C_VTG_MIN_UV 1800000 +#define HX_I2C_VTG_MAX_UV 1800000 +#define HX_I2C_LOAD_UA 10000 +#define HX_I2C_LPM_LOAD_UA 10 +#endif + +#define HIMAX_common_NAME "himax_tp" +#define HIMAX_I2C_ADDR 0x48 +#define INPUT_DEV_NAME "himax-touchscreen" + +struct himax_i2c_platform_data { + int abs_x_min; + int abs_x_max; + int abs_x_fuzz; + int abs_y_min; + int abs_y_max; + int abs_y_fuzz; + int abs_pressure_min; + int abs_pressure_max; + int abs_pressure_fuzz; + int abs_width_min; + int abs_width_max; + int screenWidth; + int screenHeight; + uint8_t fw_version; + uint8_t tw_id; + uint8_t powerOff3V3; + uint8_t cable_config[2]; + uint8_t protocol_type; + int gpio_irq; + int gpio_reset; + int gpio_3v3_en; + int (*power)(int on); + void (*reset)(void); + struct himax_virtual_key *virtual_key; + struct kobject *vk_obj; + struct kobj_attribute *vk2Use; + + struct himax_config *hx_config; + int hx_config_size; +#if defined(CONFIG_HMX_DB) + bool i2c_pull_up; + bool digital_pwr_regulator; + int reset_gpio; + u32 reset_gpio_flags; + int irq_gpio; + u32 irq_gpio_flags; + + struct regulator *vcc_ana; /*For Dragon Board*/ + struct regulator *vcc_dig; /*For Dragon Board*/ + struct regulator *vcc_i2c; /*For Dragon Board*/ +#endif +}; + + +extern int irq_enable_count; +int i2c_himax_read(struct i2c_client *client, + uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_write(struct i2c_client *client, + uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_write_command(struct i2c_client *client, + uint8_t command, uint8_t toRetry); + +int i2c_himax_master_write(struct i2c_client *client, + uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_read_command(struct i2c_client *client, + uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry); + +void himax_int_enable(int irqnum, int enable); +int himax_ts_register_interrupt(struct i2c_client *client); +void himax_rst_gpio_set(int pinnum, uint8_t value); +uint8_t himax_int_gpio_read(int pinnum); + +int himax_gpio_power_config(struct i2c_client *client, + struct himax_i2c_platform_data *pdata); + +#if defined(CONFIG_FB) +extern int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#endif +extern struct himax_ts_data *private_ts; +extern struct himax_ic_data *ic_data; +extern void himax_ts_work(struct himax_ts_data *ts); +extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); +extern int tp_rst_gpio; + +#ifdef HX_TP_PROC_DIAG +extern uint8_t getDiagCommand(void); +#endif + +int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata); +int himax_ts_pinctrl_init(struct himax_ts_data *ts); + +#endif From a1a552772ce020753628a57c0729d8c2ef0ef60d Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Tue, 13 Mar 2018 18:03:19 +0530 Subject: [PATCH 056/392] ASoC: msm: clean up bootup errors Fix errors shown during bootup to ensure robustness and enable cleaner bootup process. Change-Id: Ie63dcb1d3f05ad852bbaf1472ac3726011eb3bee Signed-off-by: Ashish Jain Signed-off-by: Dhanalakshmi Siddani --- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 67 +++++++++++++++------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 471ad025b281..6a0f0a470bd9 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -3151,6 +3151,11 @@ static const struct snd_kcontrol_new ext_ec_ref_mux_ul2 = msm_route_ec_ref_rx_enum[0], msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); +static const struct snd_kcontrol_new ext_ec_ref_mux_ul3 = + SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL3 MUX Mux", + msm_route_ec_ref_rx_enum[0], + msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); + static const struct snd_kcontrol_new ext_ec_ref_mux_ul4 = SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL4 MUX Mux", msm_route_ec_ref_rx_enum[0], @@ -3827,9 +3832,15 @@ static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), @@ -3940,15 +3951,6 @@ static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = { msm_routing_put_audio_mixer), }; -static const struct snd_kcontrol_new mi2s_hl_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, - MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, - MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, - msm_routing_put_port_mixer), -}; - static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_MI2S_RX , MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, @@ -6659,6 +6661,9 @@ static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = { SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), + SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX, + MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, + msm_routing_put_voice_stub_mixer), SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX , MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), @@ -7280,6 +7285,9 @@ static const struct snd_kcontrol_new tx_voip_mixer_controls[] = { SOC_SINGLE_EXT("TERT_MI2S_TX_Voip", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3_Voip", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, + msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = { @@ -7414,6 +7422,9 @@ static const struct snd_kcontrol_new tx_qchat_mixer_controls[] = { SOC_SINGLE_EXT("TERT_MI2S_TX_QCHAT", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), + SOC_SINGLE_EXT("PRI_TDM_TX_3_QCHAT", MSM_BACKEND_DAI_PRI_TDM_TX_3, + MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, + msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = { @@ -7441,6 +7452,9 @@ static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), @@ -8755,6 +8769,9 @@ static const struct snd_kcontrol_new sec_mi2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), @@ -9093,7 +9110,7 @@ static const struct soc_enum aanc_slim_0_rx_enum = aanc_slim_0_rx_text); static const struct snd_kcontrol_new aanc_slim_0_rx_mux[] = { - SOC_DAPM_ENUM_EXT("AANC_SLIM_0_RX MUX", aanc_slim_0_rx_enum, + SOC_ENUM_EXT("AANC_SLIM_0_RX MUX", aanc_slim_0_rx_enum, msm_routing_slim_0_rx_aanc_mux_get, msm_routing_slim_0_rx_aanc_mux_put) }; @@ -9942,6 +9959,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_OUT("MM_UL19", "MultiMedia19 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL20", "MultiMedia20 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL21", "MultiMedia21 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL28", "MultiMedia28 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL29", "MultiMedia29 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0), @@ -10280,6 +10299,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_IN("SLIMBUS_2_TX", "Slimbus2 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("QUIN_MI2S_TX", "Quinary MI2S Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("SENARY_MI2S_TX", "Senary MI2S Capture", + 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("INT_BT_SCO_RX", "Internal BT-SCO Playback", 0, 0, 0 , 0), SND_SOC_DAPM_AIF_IN("INT_BT_SCO_TX", "Internal BT-SCO Capture", @@ -10494,9 +10515,6 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_SWITCH("HFP_INT_UL_HL", SND_SOC_NOPM, 0, 0, &hfp_int_switch_mixer_controls), - SND_SOC_DAPM_MUX("SLIM_0_RX AANC MUX", SND_SOC_NOPM, 0, 0, - aanc_slim_0_rx_mux), - /* Mixer definitions */ SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0, pri_i2s_rx_mixer_controls, ARRAY_SIZE(pri_i2s_rx_mixer_controls)), @@ -10524,9 +10542,6 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_MIXER("SEC_MI2S_RX_SD1 Audio Mixer", SND_SOC_NOPM, 0, 0, secondary_mi2s_rx2_mixer_controls, ARRAY_SIZE(secondary_mi2s_rx2_mixer_controls)), - SND_SOC_DAPM_MIXER("SEC_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0, - mi2s_hl_mixer_controls, - ARRAY_SIZE(mi2s_hl_mixer_controls)), SND_SOC_DAPM_MIXER("PRI_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, primary_mi2s_rx_mixer_controls, ARRAY_SIZE(primary_mi2s_rx_mixer_controls)), @@ -10868,6 +10883,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { &ext_ec_ref_mux_ul1), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL2 MUX", SND_SOC_NOPM, 0, 0, &ext_ec_ref_mux_ul2), + SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL3 MUX", SND_SOC_NOPM, 0, 0, + &ext_ec_ref_mux_ul3), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL4 MUX", SND_SOC_NOPM, 0, 0, &ext_ec_ref_mux_ul4), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL5 MUX", SND_SOC_NOPM, 0, 0, @@ -10884,6 +10901,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { &ext_ec_ref_mux_ul18), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL19 MUX", SND_SOC_NOPM, 0, 0, &ext_ec_ref_mux_ul19), + SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL28 MUX", SND_SOC_NOPM, 0, 0, + &ext_ec_ref_mux_ul28), + SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL29 MUX", SND_SOC_NOPM, 0, 0, + &ext_ec_ref_mux_ul29), }; static const struct snd_soc_dapm_route intercon[] = { @@ -11143,9 +11164,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_MI2S_RX_SD1 Audio Mixer", "MultiMedia6", "MM_DL6"}, {"SEC_MI2S_RX_SD1", NULL, "SEC_MI2S_RX_SD1 Audio Mixer"}, - {"SEC_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, - {"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, - {"PRI_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, {"PRI_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, {"PRI_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, @@ -11974,6 +11992,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"INTERNAL_BT_SCO_RX_Voice Mixer", "QCHAT", "QCHAT_DL"}, {"INTERNAL_BT_SCO_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"}, {"INTERNAL_BT_SCO_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"}, + {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"}, + {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"}, {"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"}, {"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"}, @@ -12122,6 +12142,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"AUDIO_REF_EC_UL2 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"}, {"AUDIO_REF_EC_UL2 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"}, + {"AUDIO_REF_EC_UL3 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"}, + {"AUDIO_REF_EC_UL3 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"}, + {"AUDIO_REF_EC_UL3 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"}, + {"AUDIO_REF_EC_UL3 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"}, + {"AUDIO_REF_EC_UL4 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"}, {"AUDIO_REF_EC_UL4 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"}, {"AUDIO_REF_EC_UL4 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"}, @@ -12367,6 +12392,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"QCHAT_Tx Mixer", "MI2S_TX_QCHAT", "MI2S_TX"}, {"QCHAT_Tx Mixer", "PRI_MI2S_TX_QCHAT", "PRI_MI2S_TX"}, {"QCHAT_Tx Mixer", "TERT_MI2S_TX_QCHAT", "TERT_MI2S_TX"}, + {"QCHAT_Tx Mixer", "PRI_TDM_TX_3_QCHAT", "PRI_TDM_TX_3"}, {"QCHAT_UL", NULL, "QCHAT_Tx Mixer"}, {"INT_FM_RX", NULL, "INTFM_DL_HL"}, @@ -12801,8 +12827,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_1_RX Mixer", "Voice2 Stub", "VOICE2_STUB_DL"}, {"SLIMBUS_1_RX Mixer", "VoLTE Stub", "VOLTE_STUB_DL"}, {"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"}, - {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"}, - {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"}, {"AFE_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"}, {"AFE_PCM_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"}, {"AFE_PCM_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"}, @@ -12863,6 +12887,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"SEC_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"SEC_MI2S_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, + {"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Port Mixer"}, {"TERT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, From 0532d6826dda6085fba4576a5dac93452f56d74f Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 8 Dec 2017 15:13:27 +0000 Subject: [PATCH 057/392] KEYS: add missing permission check for request_key() destination When the request_key() syscall is not passed a destination keyring, it links the requested key (if constructed) into the "default" request-key keyring. This should require Write permission to the keyring. However, there is actually no permission check. This can be abused to add keys to any keyring to which only Search permission is granted. This is because Search permission allows joining the keyring. keyctl_set_reqkey_keyring(KEY_REQKEY_DEFL_SESSION_KEYRING) then will set the default request-key keyring to the session keyring. Then, request_key() can be used to add keys to the keyring. Both negatively and positively instantiated keys can be added using this method. Adding negative keys is trivial. Adding a positive key is a bit trickier. It requires that either /sbin/request-key positively instantiates the key, or that another thread adds the key to the process keyring at just the right time, such that request_key() misses it initially but then finds it in construct_alloc_key(). Fix this bug by checking for Write permission to the keyring in construct_get_dest_keyring() when the default keyring is being used. We don't do the permission check for non-default keyrings because that was already done by the earlier call to lookup_user_key(). Also, request_key_and_link() is currently passed a 'struct key *' rather than a key_ref_t, so the "possessed" bit is unavailable. We also don't do the permission check for the "requestor keyring", to continue to support the use case described by commit 8bbf4976b59f ("KEYS: Alter use of key instantiation link-to-keyring argument") where /sbin/request-key recursively calls request_key() to add keys to the original requestor's destination keyring. (I don't know of any users who actually do that, though...) Change-Id: I3603fec8fab929d7636d7223901f16dc8d8026cc Fixes: 3e30148c3d52 ("[PATCH] Keys: Make request-key create an authorisation key") Cc: # v2.6.13+ Signed-off-by: Eric Biggers Signed-off-by: David Howells Git-commit: 4dca6ea1d9432052afb06baf2e3ae78188a4410b Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Srinivasa Rao Kuppala Signed-off-by: Chetan C R --- security/keys/request_key.c | 49 ++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 0c7aea4dea54..8117a774ee5d 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -250,11 +250,12 @@ static int construct_key(struct key *key, const void *callout_info, * The keyring selected is returned with an extra reference upon it which the * caller must release. */ -static void construct_get_dest_keyring(struct key **_dest_keyring) +static int construct_get_dest_keyring(struct key **_dest_keyring) { struct request_key_auth *rka; const struct cred *cred = current_cred(); struct key *dest_keyring = *_dest_keyring, *authkey; + int ret; kenter("%p", dest_keyring); @@ -263,6 +264,8 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) /* the caller supplied one */ key_get(dest_keyring); } else { + bool do_perm_check = true; + /* use a default keyring; falling through the cases until we * find one that we actually have */ switch (cred->jit_keyring) { @@ -277,8 +280,10 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) dest_keyring = key_get(rka->dest_keyring); up_read(&authkey->sem); - if (dest_keyring) + if (dest_keyring) { + do_perm_check = false; break; + } } case KEY_REQKEY_DEFL_THREAD_KEYRING: @@ -313,11 +318,29 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) default: BUG(); } + + /* + * Require Write permission on the keyring. This is essential + * because the default keyring may be the session keyring, and + * joining a keyring only requires Search permission. + * + * However, this check is skipped for the "requestor keyring" so + * that /sbin/request-key can itself use request_key() to add + * keys to the original requestor's destination keyring. + */ + if (dest_keyring && do_perm_check) { + ret = key_permission(make_key_ref(dest_keyring, 1), + KEY_NEED_WRITE); + if (ret) { + key_put(dest_keyring); + return ret; + } + } } *_dest_keyring = dest_keyring; kleave(" [dk %d]", key_serial(dest_keyring)); - return; + return 0; } /* @@ -439,11 +462,18 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, kenter(""); - user = key_user_lookup(current_fsuid()); - if (!user) - return ERR_PTR(-ENOMEM); + if (ctx->index_key.type == &key_type_keyring) + return ERR_PTR(-EPERM); + + ret = construct_get_dest_keyring(&dest_keyring); + if (ret) + goto error; - construct_get_dest_keyring(&dest_keyring); + user = key_user_lookup(current_fsuid()); + if (!user) { + ret = -ENOMEM; + goto error_put_dest_keyring; + } ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key); key_user_put(user); @@ -458,7 +488,7 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, } else if (ret == -EINPROGRESS) { ret = 0; } else { - goto couldnt_alloc_key; + goto error_put_dest_keyring; } key_put(dest_keyring); @@ -468,8 +498,9 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, construction_failed: key_negate_and_link(key, key_negative_timeout, NULL, NULL); key_put(key); -couldnt_alloc_key: +error_put_dest_keyring: key_put(dest_keyring); +error: kleave(" = %d", ret); return ERR_PTR(ret); } From 13c00bdde0874cbd61cd3e3a3b727511f41b3114 Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Tue, 22 May 2018 19:12:37 +0530 Subject: [PATCH 058/392] ARM: dts: msm8909go: Enable supported crypto algos These algos are needed for full disk encryption. Change-Id: Ieff3e5cb9f96066b3a24d1cb2377116fcacecf00 Signed-off-by: Neeraj Soni --- arch/arm/boot/dts/qcom/msm8909.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msm8909.dtsi b/arch/arm/boot/dts/qcom/msm8909.dtsi index fd10716b1c6e..7db70e797f75 100644 --- a/arch/arm/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909.dtsi @@ -1861,6 +1861,10 @@ qcom,use-sw-aes-cbc-ecb-ctr-algo; qcom,use-sw-aes-xts-algo; qcom,use-sw-ahash-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-hmac-algo; + qcom,use-sw-aead-algo; + status = "disabled"; qcom,ce-opp-freq = <100000000>; }; From 15216475bf6adee960ac03e7594503a0e066f3c5 Mon Sep 17 00:00:00 2001 From: Balachandra C S Date: Wed, 30 May 2018 11:45:21 +0530 Subject: [PATCH 059/392] drivers: net: can: Add timestamp adjustment for frames in k61 driver Correct the frame timstamp based on the controller and host time differences. Change-Id: I6f359750190e9d3691249a1b25326a047aadefc3 Signed-off-by: Balachandra C S --- drivers/net/can/spi/k61.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/net/can/spi/k61.c b/drivers/net/can/spi/k61.c index 4668d40a1612..303fc95a5486 100644 --- a/drivers/net/can/spi/k61.c +++ b/drivers/net/can/spi/k61.c @@ -60,6 +60,7 @@ struct k61_can { int cmd_result; int bits_per_word; int reset_delay_msec; + s64 time_diff; }; struct k61_netdev_privdata { @@ -97,6 +98,7 @@ struct spi_miso { /* TLV for MISO line */ #define CMD_CAN_DATA_BUFF_REMOVE 0x88 #define CMD_CAN_RELEASE_BUFFER 0x89 #define CMD_CAN_DATA_BUFF_REMOVE_ALL 0x8A +#define CMD_UPDATE_TIME_INFO 0x9D #define IOCTL_RELEASE_CAN_BUFFER (SIOCDEVPRIVATE + 0) #define IOCTL_ENABLE_BUFFERING (SIOCDEVPRIVATE + 1) @@ -112,7 +114,7 @@ struct can_fw_resp { } __packed; struct can_write_req { - u32 ts; + u64 ts; u32 mid; u8 dlc; u8 data[]; @@ -123,7 +125,7 @@ struct can_write_resp { } __packed; struct can_receive_frame { - u32 ts; + u64 ts; u32 mid; u8 dlc; u8 data[]; @@ -136,6 +138,10 @@ struct can_add_filter_req { u8 type; } __packed; +struct can_time_info { + u64 time; +} __packed; + static struct can_bittiming_const k61_bittiming_const = { .name = "k61", .tseg1_min = 4, @@ -199,8 +205,7 @@ static void k61_receive_frame(struct k61_can *priv_data, struct can_frame *cf; struct sk_buff *skb; struct skb_shared_hwtstamps *skt; - struct timeval tv; - static int msec; + ktime_t nsec; struct net_device *netdev; int i; @@ -217,7 +222,7 @@ static void k61_receive_frame(struct k61_can *priv_data, return; } - LOGDI("rcv frame %d %x %d %x %x %x %x %x %x %x %x\n", + LOGDI("rcv frame %llu %x %d %x %x %x %x %x %x %x %x\n", frame->ts, frame->mid, frame->dlc, frame->data[0], frame->data[1], frame->data[2], frame->data[3], frame->data[4], frame->data[5], frame->data[6], frame->data[7]); @@ -227,13 +232,11 @@ static void k61_receive_frame(struct k61_can *priv_data, for (i = 0; i < cf->can_dlc; i++) cf->data[i] = frame->data[i]; - msec = le32_to_cpu(frame->ts); - tv.tv_sec = msec / 1000; - tv.tv_usec = (msec - tv.tv_sec * 1000) * 1000; + nsec = ms_to_ktime(le64_to_cpu(frame->ts) + priv_data->time_diff); skt = skb_hwtstamps(skb); - skt->hwtstamp = timeval_to_ktime(tv); + skt->hwtstamp = nsec; LOGDI(" hwtstamp %lld\n", ktime_to_ms(skt->hwtstamp)); - skb->tstamp = timeval_to_ktime(tv); + skb->tstamp = nsec; netif_rx(skb); netdev->stats.rx_packets++; netdev->stats.rx_bytes += cf->can_dlc; @@ -243,6 +246,9 @@ static void k61_process_response(struct k61_can *priv_data, struct spi_miso *resp) { int ret = 0; + u64 mstime; + ktime_t ktime_now; + LOGDI("<%x %2d [%d]\n", resp->cmd, resp->len, resp->seq); if (resp->cmd == CMD_CAN_RECEIVE_FRAME) { struct can_receive_frame *frame = @@ -253,6 +259,12 @@ static void k61_process_response(struct k61_can *priv_data, dev_info(&priv_data->spidev->dev, "fw %d.%d.%d", fw_resp->maj, fw_resp->min, fw_resp->ver); + } else if (resp->cmd == CMD_UPDATE_TIME_INFO) { + struct can_time_info *time_data = + (struct can_time_info *)resp->data; + ktime_now = ktime_get_boottime(); + mstime = ktime_to_ms(ktime_now); + priv_data->time_diff = mstime - (le64_to_cpu(time_data->time)); } if (resp->cmd == priv_data->wait_cmd) { From 53fc78e5dae31fe35aa90a4c4ed7930630fcabf1 Mon Sep 17 00:00:00 2001 From: Balachandra C S Date: Wed, 4 Jul 2018 19:50:56 +0530 Subject: [PATCH 060/392] drivers: net: can: Inform power states to k61 controller K61 controller needs to be aware of host power state to decide if a timestamp message can be sent to host or not and also modify irq type to be read from device tree as irq type may vary among different targets. Change-Id: I9ad8acc02ad6509579e78c87aaa3b4b15561c139 Signed-off-by: Balachandra C S --- drivers/net/can/spi/k61.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/spi/k61.c b/drivers/net/can/spi/k61.c index 303fc95a5486..6bb9204dfc2f 100644 --- a/drivers/net/can/spi/k61.c +++ b/drivers/net/can/spi/k61.c @@ -99,6 +99,8 @@ struct spi_miso { /* TLV for MISO line */ #define CMD_CAN_RELEASE_BUFFER 0x89 #define CMD_CAN_DATA_BUFF_REMOVE_ALL 0x8A #define CMD_UPDATE_TIME_INFO 0x9D +#define CMD_SUSPEND_EVENT 0x9E +#define CMD_RESUME_EVENT 0x9F #define IOCTL_RELEASE_CAN_BUFFER (SIOCDEVPRIVATE + 0) #define IOCTL_ENABLE_BUFFERING (SIOCDEVPRIVATE + 1) @@ -389,6 +391,30 @@ static int k61_query_firmware_version(struct k61_can *priv_data) return ret; } +static int k61_notify_power_events(struct k61_can *priv_data, u8 event_type) +{ + char *tx_buf, *rx_buf; + int ret; + struct spi_mosi *req; + + mutex_lock(&priv_data->spi_lock); + tx_buf = priv_data->tx_buf; + rx_buf = priv_data->rx_buf; + memset(tx_buf, 0, XFER_BUFFER_SIZE); + memset(rx_buf, 0, XFER_BUFFER_SIZE); + priv_data->xfer_length = XFER_BUFFER_SIZE; + + req = (struct spi_mosi *)tx_buf; + req->cmd = event_type; + req->len = 0; + req->seq = atomic_inc_return(&priv_data->msg_seq); + + ret = k61_do_spi_transaction(priv_data); + mutex_unlock(&priv_data->spi_lock); + + return ret; +} + static int k61_can_write(struct k61_can *priv_data, struct can_frame *cf) { char *tx_buf, *rx_buf; @@ -825,6 +851,7 @@ static int k61_probe(struct spi_device *spi) int err, retry = 0, query_err = -1; struct k61_can *priv_data; struct device *dev; + u32 irq_type; dev = &spi->dev; dev_dbg(dev, "k61_probe"); @@ -881,8 +908,11 @@ static int k61_probe(struct spi_device *spi) goto unregister_candev; } + irq_type = irq_get_trigger_type(spi->irq); + if (irq_type == IRQ_TYPE_NONE) + irq_type = IRQ_TYPE_EDGE_FALLING; err = request_threaded_irq(spi->irq, NULL, k61_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + irq_type | IRQF_ONESHOT, "k61", priv_data); if (err) { dev_err(dev, "Failed to request irq: %d", err); @@ -936,7 +966,10 @@ static const struct of_device_id k61_match_table[] = { static int k61_suspend(struct device *dev) { struct spi_device *spi = to_spi_device(dev); + struct k61_can *priv_data = spi_get_drvdata(spi); + u8 power_event = CMD_SUSPEND_EVENT; + k61_notify_power_events(priv_data, power_event); enable_irq_wake(spi->irq); return 0; } @@ -945,9 +978,10 @@ static int k61_resume(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct k61_can *priv_data = spi_get_drvdata(spi); + u8 power_event = CMD_RESUME_EVENT; disable_irq_wake(spi->irq); - k61_rx_message(priv_data); + k61_notify_power_events(priv_data, power_event); return 0; } From 14a37e56f7fb3e6df9a8955049782af2eb2e19b7 Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Thu, 22 Dec 2016 12:11:26 +0530 Subject: [PATCH 061/392] ASoC: msm: qdsp6v2: Add support to query adsp version Q6 core service provides API to query ADSP version. Update the apr with get()/set() to use this adsp version by platform/machine drivers. Signed-off-by: Surendar karka Change-Id: I2466f4eba636ce41e5eb9a75e2e5e75a069fd0ee Signed-off-by: Dhanalakshmi Siddani --- include/sound/q6core.h | 21 +++++++- sound/soc/msm/qdsp6v2/q6core.c | 93 ++++++++++++++++++++++++++++++++-- 2 files changed, 110 insertions(+), 4 deletions(-) diff --git a/include/sound/q6core.h b/include/sound/q6core.h index f21e790ce600..975eda177664 100644 --- a/include/sound/q6core.h +++ b/include/sound/q6core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -157,4 +157,23 @@ struct avcs_cmd_deregister_topologies { int32_t core_set_license(uint32_t key, uint32_t module_id); int32_t core_get_license_status(uint32_t module_id); +#define AVCS_GET_VERSIONS 0x00012905 +struct avcs_cmd_get_version_result { + struct apr_hdr hdr; + uint32_t id; +}; +#define AVCS_GET_VERSIONS_RSP 0x00012906 + +#define AVCS_CMDRSP_Q6_ID_2_6 0x00040000 +#define AVCS_CMDRSP_Q6_ID_2_7 0x00040001 +#define AVCS_CMDRSP_Q6_ID_2_8 0x00040002 + +enum q6_subsys_image { + Q6_SUBSYS_AVS2_6 = 1, + Q6_SUBSYS_AVS2_7, + Q6_SUBSYS_AVS2_8, + Q6_SUBSYS_INVALID, +}; +enum q6_subsys_image q6core_get_avs_version(void); +int core_get_adsp_ver(void); #endif /* __Q6CORE_H__ */ diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c index 3fedc869f024..2d9f68a2b47b 100644 --- a/sound/soc/msm/qdsp6v2/q6core.c +++ b/sound/soc/msm/qdsp6v2/q6core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -57,7 +57,8 @@ struct q6core_str { u32 bus_bw_resp_received; enum cmd_flags { FLAG_NONE, - FLAG_CMDRSP_LICENSE_RESULT + FLAG_CMDRSP_LICENSE_RESULT, + FLAG_AVCS_GET_VERSIONS_RESULT, } cmd_resp_received_flag; u32 avcs_fwk_ver_resp_received; struct mutex cmd_lock; @@ -71,6 +72,7 @@ struct q6core_str { uint32_t mem_map_cal_handle; int32_t adsp_status; struct q6core_avcs_ver_info q6core_avcs_ver_info; + u32 q6_core_avs_version; }; static struct q6core_str q6core_lcl; @@ -180,7 +182,33 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv) q6core_lcl.bus_bw_resp_received = 1; wake_up(&q6core_lcl.bus_bw_req_wait); break; - case AVCS_CMDRSP_GET_LICENSE_VALIDATION_RESULT: + case AVCS_GET_VERSIONS_RSP: + payload1 = data->payload; + pr_debug("%s: Received ADSP version response[3]0x%x\n", + __func__, payload1[3]); + q6core_lcl.cmd_resp_received_flag = + FLAG_AVCS_GET_VERSIONS_RESULT; + if (AVCS_CMDRSP_Q6_ID_2_6 == payload1[3]) { + q6core_lcl.q6_core_avs_version = Q6_SUBSYS_AVS2_6; + pr_debug("%s: Received ADSP version as 2.6\n", + __func__); + } else if (AVCS_CMDRSP_Q6_ID_2_7 == payload1[3]) { + q6core_lcl.q6_core_avs_version = Q6_SUBSYS_AVS2_7; + pr_debug("%s: Received ADSP version as 2.7\n", + __func__); + } else if (AVCS_CMDRSP_Q6_ID_2_8 == payload1[3]) { + q6core_lcl.q6_core_avs_version = Q6_SUBSYS_AVS2_8; + pr_info("%s: Received ADSP version as 2.8\n", + __func__); + } else { + pr_err("%s: ADSP version is neither 2.6 nor 2.7\n", + __func__); + q6core_lcl.q6_core_avs_version = Q6_SUBSYS_INVALID; + } + wake_up(&q6core_lcl.cmd_req_wait); + break; + + case AVCS_CMDRSP_GET_LICENSE_VALIDATION_RESULT: payload1 = data->payload; pr_debug("%s: cmd = LICENSE_VALIDATION_RESULT, result = 0x%x\n", __func__, payload1[0]); @@ -421,6 +449,65 @@ int32_t core_set_license(uint32_t key, uint32_t module_id) return rc; } +int core_get_adsp_ver(void) +{ + struct avcs_cmd_get_version_result get_aver_cmd; + int ret = 0; + + mutex_lock(&(q6core_lcl.cmd_lock)); + ocm_core_open(); + if (q6core_lcl.core_handle_q == NULL) { + pr_err("%s: apr registration for CORE failed\n", __func__); + ret = -ENODEV; + goto fail_cmd; + } + + get_aver_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + get_aver_cmd.hdr.pkt_size = sizeof(get_aver_cmd); + get_aver_cmd.hdr.src_port = 0; + get_aver_cmd.hdr.dest_port = 0; + get_aver_cmd.hdr.token = 0; + get_aver_cmd.hdr.opcode = AVCS_GET_VERSIONS; + + ret = apr_send_pkt(q6core_lcl.core_handle_q, + (uint32_t *) &get_aver_cmd); + if (ret < 0) { + pr_err("%s: Core get DSP version request failed, err %d\n", + __func__, ret); + ret = -EREMOTE; + goto fail_cmd; + } + + q6core_lcl.cmd_resp_received_flag &= ~(FLAG_AVCS_GET_VERSIONS_RESULT); + mutex_unlock(&(q6core_lcl.cmd_lock)); + ret = wait_event_timeout(q6core_lcl.cmd_req_wait, + (q6core_lcl.cmd_resp_received_flag == + FLAG_AVCS_GET_VERSIONS_RESULT), + msecs_to_jiffies(TIMEOUT_MS)); + mutex_lock(&(q6core_lcl.cmd_lock)); + if (!ret) { + pr_err("%s: wait_event timeout for AVCS_GET_VERSIONS_RESULT\n", + __func__); + ret = -ETIMEDOUT; + goto fail_cmd; + } + q6core_lcl.cmd_resp_received_flag &= ~(FLAG_AVCS_GET_VERSIONS_RESULT); + +fail_cmd: + if (ret < 0) + q6core_lcl.q6_core_avs_version = Q6_SUBSYS_INVALID; + mutex_unlock(&(q6core_lcl.cmd_lock)); + return ret; +} + +enum q6_subsys_image q6core_get_avs_version(void) +{ + if (q6core_lcl.q6_core_avs_version == 0) + core_get_adsp_ver(); + return q6core_lcl.q6_core_avs_version; +} + int32_t core_get_license_status(uint32_t module_id) { struct avcs_cmd_get_license_validation_result get_lvr_cmd; From 5a286b5e3980c20116eece0d7d9d3cbe8eb625e9 Mon Sep 17 00:00:00 2001 From: gaolez Date: Mon, 8 Jan 2018 14:15:25 +0800 Subject: [PATCH 062/392] msm: wlan: Support ETSI13 regulatory domain ETSI13 regulatory domain is created to support channel 149~173 with 14dBm tx power, including 46 countries: AL,AT,BE,BA,BG,HR,CY,CZ,DK, EE,FI,FR,GF,PF,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MK,MT,MQ,MD,MC,ME,NL, AN,NO,PL,PT,RO,PM,VC,RS,SK,SI,ES,SE,CH,TR,GB. Change-Id: Idc575983645670e9410d831f2eb80186326926f8 Signed-off-by: Gaole Zhang --- net/wireless/db.txt | 342 +++++++------------------------------------- 1 file changed, 49 insertions(+), 293 deletions(-) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 6d2d3934ee61..983e3aff57bb 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -37,10 +37,10 @@ country AI: DFS-ETSI country AL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5730 @ 160), (30), DFS - (5735 - 5875 @ 80), (14) + (5150 - 5250 @ 80), (23), AUTO-BW + (5250 - 5350 @ 80), (23), DFS, AUTO-BW + (5470 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country AM: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -52,6 +52,7 @@ country AN: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country AR: (2402 - 2482 @ 40), (36) @@ -73,15 +74,7 @@ country AT: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -109,6 +102,7 @@ country BA: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -127,15 +121,7 @@ country BE: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -151,15 +137,7 @@ country BG: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -243,15 +221,7 @@ country CH: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) country CI: DFS-FCC (2402 - 2482 @ 40), (20) @@ -302,15 +272,7 @@ country CY: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -323,15 +285,7 @@ country CZ: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -353,15 +307,7 @@ country DE: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -370,15 +316,7 @@ country DK: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -412,15 +350,7 @@ country EE: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -434,15 +364,7 @@ country ES: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -457,15 +379,7 @@ country FI: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -481,15 +395,7 @@ country FR: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -498,15 +404,7 @@ country GB: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -529,6 +427,7 @@ country GF: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country GH: DFS-FCC (2402 - 2482 @ 40), (20) @@ -560,15 +459,7 @@ country GR: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -607,15 +498,7 @@ country HR: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -631,15 +514,7 @@ country HU: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -653,16 +528,7 @@ country IE: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -687,15 +553,7 @@ country IS: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -704,15 +562,7 @@ country IT: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -800,15 +650,7 @@ country LI: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) country LK: DFS-FCC (2402 - 2482 @ 40), (20) @@ -828,15 +670,7 @@ country LT: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -845,15 +679,7 @@ country LU: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -862,15 +688,7 @@ country LV: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -884,18 +702,21 @@ country MC: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country MD: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country ME: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country MF: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -915,6 +736,7 @@ country MK: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -944,6 +766,7 @@ country MQ: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country MR: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -956,15 +779,7 @@ country MT: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1025,15 +840,7 @@ country NL: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1042,15 +849,7 @@ country NO: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1091,6 +890,7 @@ country PF: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country PG: DFS-FCC (2402 - 2482 @ 40), (20) @@ -1115,15 +915,7 @@ country PL: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1132,6 +924,7 @@ country PM: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country PR: DFS-FCC (2402 - 2472 @ 40), (30) @@ -1145,15 +938,7 @@ country PT: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1189,15 +974,7 @@ country RO: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1208,6 +985,7 @@ country RS: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1237,15 +1015,7 @@ country SE: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1261,15 +1031,7 @@ country SI: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1278,15 +1040,7 @@ country SK: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1344,6 +1098,7 @@ country TR: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1427,6 +1182,7 @@ country VC: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country VE: DFS-FCC (2402 - 2482 @ 40), (30) From 847d2b8851cfc18283eb6e82a2d0cac3d1b35ad1 Mon Sep 17 00:00:00 2001 From: gaolez Date: Wed, 11 Jul 2018 12:05:29 +0800 Subject: [PATCH 063/392] ARM: dts: msm: Adjust sdio clock as 177Mhz for apq8053 Adjust sdio clock as 177Mhz for apq8053. Change-Id: Ic0970cde2e41266439443d83bd161e71fc92d0da Signed-off-by: Gaole Zhang --- arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi index 8649b2000e70..0cf97ceb1ca7 100644 --- a/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi +++ b/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi @@ -408,7 +408,8 @@ 2 &tlmm 133 0>; interrupt-names = "hc_irq", "pwr_irq", "status_irq"; - qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 177770000>; qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; status = "ok"; From 22be17bc2a2ac719451272127c987eafc9f15161 Mon Sep 17 00:00:00 2001 From: David Dai Date: Thu, 22 Mar 2018 17:00:57 -0700 Subject: [PATCH 064/392] msm: msm_bus: Fix error handling in msm_bus_device_init Correctly free pointers allocated by kzalloc. Remove devm_kfree in error handling as device associated memory is automatically freed upon destruction of device. Always use put_device instead of kfree on initialized device. Change-Id: Icbd88e9ccd42fedb4fbce5eff69248c3fceffc02 Signed-off-by: David Dai Signed-off-by: Srinivasarao P --- .../msm/msm_bus/msm_bus_fabric_adhoc.c | 48 +++++++------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c b/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c index 146d7c6d70a8..816b3be86a9f 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c +++ b/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c @@ -1012,10 +1012,8 @@ static struct device *msm_bus_device_init( bus_node = kzalloc(sizeof(struct msm_bus_node_device_type), GFP_KERNEL); if (!bus_node) { - MSM_BUS_ERR("%s:Bus node alloc failed\n", __func__); - kfree(bus_dev); - bus_dev = NULL; - goto exit_device_init; + ret = -ENOMEM; + goto err_device_init; } bus_dev = &bus_node->dev; device_initialize(bus_dev); @@ -1023,47 +1021,37 @@ static struct device *msm_bus_device_init( node_info = devm_kzalloc(bus_dev, sizeof(struct msm_bus_node_info_type), GFP_KERNEL); if (!node_info) { - MSM_BUS_ERR("%s:Bus node info alloc failed\n", __func__); - devm_kfree(bus_dev, bus_node); - kfree(bus_dev); - bus_dev = NULL; - goto exit_device_init; + ret = -ENOMEM; + goto err_put_device; } bus_node->node_info = node_info; bus_node->ap_owned = pdata->ap_owned; bus_dev->of_node = pdata->of_node; - if (msm_bus_copy_node_info(pdata, bus_dev) < 0) { - devm_kfree(bus_dev, bus_node); - devm_kfree(bus_dev, node_info); - kfree(bus_dev); - bus_dev = NULL; - goto exit_device_init; - } + ret = msm_bus_copy_node_info(pdata, bus_dev); + if (ret) + goto err_put_device; bus_dev->bus = &msm_bus_type; dev_set_name(bus_dev, bus_node->node_info->name); ret = device_add(bus_dev); - if (ret < 0) { + if (ret) { MSM_BUS_ERR("%s: Error registering device %d", __func__, pdata->node_info->id); - devm_kfree(bus_dev, bus_node); - devm_kfree(bus_dev, node_info->dev_connections); - devm_kfree(bus_dev, node_info->connections); - devm_kfree(bus_dev, node_info->black_connections); - devm_kfree(bus_dev, node_info->black_listed_connections); - devm_kfree(bus_dev, node_info); - kfree(bus_dev); - bus_dev = NULL; - goto exit_device_init; + goto err_put_device; } device_create_file(bus_dev, &dev_attr_bw); INIT_LIST_HEAD(&bus_node->devlist); - -exit_device_init: return bus_dev; + +err_put_device: + put_device(bus_dev); + bus_dev = NULL; + kfree(bus_node); +err_device_init: + return ERR_PTR(ret); } static int msm_bus_setup_dev_conn(struct device *bus_dev, void *data) @@ -1258,10 +1246,10 @@ static int msm_bus_device_probe(struct platform_device *pdev) node_dev = msm_bus_device_init(&pdata->info[i]); - if (!node_dev) { + if (IS_ERR(node_dev)) { MSM_BUS_ERR("%s: Error during dev init for %d", __func__, pdata->info[i].node_info->id); - ret = -ENXIO; + ret = PTR_ERR(node_dev); goto exit_device_probe; } From c67fc83d019ce95ef7af2f23b63f5c6e7060f7d5 Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Thu, 22 Dec 2016 15:07:53 +0530 Subject: [PATCH 065/392] ASoC: msm: add support for AVS 2.8 in compress driver Updating compress driver to use session_time api based on AVS version. Change-Id: I8f5ffc6fef5add01b5d61d3381ff6615e95da404 Signed-off-by: Surendar karka Signed-off-by: Dhanalakshmi Siddani --- sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c | 51 ++++++++++++---------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 8006ece375aa..aa370a9deca8 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -104,7 +105,6 @@ struct msm_compr_pdata { uint32_t volume[MSM_FRONTEND_DAI_MAX][2]; /* For both L & R */ struct msm_compr_audio_effects *audio_effects[MSM_FRONTEND_DAI_MAX]; bool use_dsp_gapless_mode; - bool use_legacy_api; /* indicates use older asm apis*/ struct msm_compr_dec_params *dec_params[MSM_FRONTEND_DAI_MAX]; struct msm_compr_ch_map *ch_map[MSM_FRONTEND_DAI_MAX]; bool is_in_use[MSM_FRONTEND_DAI_MAX]; @@ -2230,13 +2230,22 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) /* * Cache this time as last known time */ - if (pdata->use_legacy_api) + switch (q6core_get_avs_version()) { + case (Q6_SUBSYS_AVS2_6): q6asm_get_session_time_legacy( prtd->audio_client, &prtd->marker_timestamp); - else + break; + case (Q6_SUBSYS_AVS2_7): + case (Q6_SUBSYS_AVS2_8): q6asm_get_session_time(prtd->audio_client, &prtd->marker_timestamp); + break; + case (Q6_SUBSYS_INVALID): + default: + pr_err("%s: INVALID AVS IMAGE\n", __func__); + break; + } spin_lock_irqsave(&prtd->lock, flags); /* @@ -2416,13 +2425,22 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream, stream. */ if (!first_buffer || gapless_transition) { - - if (pdata->use_legacy_api) - rc = q6asm_get_session_time_legacy( - prtd->audio_client, &prtd->marker_timestamp); - else - rc = q6asm_get_session_time( - prtd->audio_client, &prtd->marker_timestamp); + switch (q6core_get_avs_version()) { + case (Q6_SUBSYS_AVS2_6): + q6asm_get_session_time_legacy( + prtd->audio_client, + &prtd->marker_timestamp); + break; + case (Q6_SUBSYS_AVS2_7): + case (Q6_SUBSYS_AVS2_8): + q6asm_get_session_time(prtd->audio_client, + &prtd->marker_timestamp); + break; + case (Q6_SUBSYS_INVALID): + default: + pr_err("%s: INVALID AVS IMAGE\n", __func__); + break; + } if (rc < 0) { pr_err("%s: Get Session Time return =%lld\n", __func__, timestamp); @@ -3385,8 +3403,6 @@ static int msm_compr_probe(struct snd_soc_platform *platform) { struct msm_compr_pdata *pdata; int i; - int rc; - const char *qdsp_version; pr_debug("%s\n", __func__); pdata = (struct msm_compr_pdata *) @@ -3409,17 +3425,6 @@ static int msm_compr_probe(struct snd_soc_platform *platform) snd_soc_add_platform_controls(platform, msm_compr_gapless_controls, ARRAY_SIZE(msm_compr_gapless_controls)); - rc = of_property_read_string(platform->dev->of_node, - "qcom,adsp-version", &qdsp_version); - if (!rc) { - if (!strcmp(qdsp_version, "MDSP 1.2")) - pdata->use_legacy_api = true; - else - pdata->use_legacy_api = false; - } else - pdata->use_legacy_api = false; - - pr_debug("%s: use legacy api %d\n", __func__, pdata->use_legacy_api); /* * use_dsp_gapless_mode part of platform data(pdata) is updated from HAL * through a mixer control before compress driver is opened. The mixer From 7a73ad6ee2bba05fc0c2a627ec8d2057c0b47655 Mon Sep 17 00:00:00 2001 From: gaolez Date: Mon, 29 Jan 2018 14:01:06 +0800 Subject: [PATCH 066/392] msm: wlan: ETSI13 shall support 144 channel ETSI13 shall support 144 channel Change-Id: I620c8487d4754d79e0b8af25695a3b85c057a85f Signed-off-by: Gaole Zhang --- net/wireless/db.txt | 188 ++++++++++++++++++++++---------------------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 983e3aff57bb..d9738ccfe855 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -37,10 +37,10 @@ country AI: DFS-ETSI country AL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5150 - 5250 @ 80), (23), AUTO-BW - (5250 - 5350 @ 80), (23), DFS, AUTO-BW - (5470 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country AM: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -51,8 +51,8 @@ country AN: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country AR: (2402 - 2482 @ 40), (36) @@ -73,8 +73,8 @@ country AT: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -101,8 +101,8 @@ country BA: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -120,8 +120,8 @@ country BE: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -136,8 +136,8 @@ country BG: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -220,8 +220,8 @@ country CH: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country CI: DFS-FCC (2402 - 2482 @ 40), (20) @@ -271,8 +271,8 @@ country CY: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -284,8 +284,8 @@ country CZ: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -306,8 +306,8 @@ country DE: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -315,8 +315,8 @@ country DK: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -349,8 +349,8 @@ country EE: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -363,8 +363,8 @@ country ES: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -378,8 +378,8 @@ country FI: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -394,8 +394,8 @@ country FR: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -403,8 +403,8 @@ country GB: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -426,8 +426,8 @@ country GF: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country GH: DFS-FCC (2402 - 2482 @ 40), (20) @@ -458,8 +458,8 @@ country GR: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -497,8 +497,8 @@ country HR: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -513,8 +513,8 @@ country HU: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -527,8 +527,8 @@ country IE: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -552,8 +552,8 @@ country IS: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -561,8 +561,8 @@ country IT: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -649,8 +649,8 @@ country LI: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country LK: DFS-FCC (2402 - 2482 @ 40), (20) @@ -669,8 +669,8 @@ country LT: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -678,8 +678,8 @@ country LU: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -687,8 +687,8 @@ country LV: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -701,22 +701,22 @@ country MC: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country MD: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country ME: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country MF: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -735,8 +735,8 @@ country MK: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -765,8 +765,8 @@ country MQ: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country MR: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -778,8 +778,8 @@ country MT: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -839,8 +839,8 @@ country NL: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -848,8 +848,8 @@ country NO: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -889,8 +889,8 @@ country PF: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country PG: DFS-FCC (2402 - 2482 @ 40), (20) @@ -914,8 +914,8 @@ country PL: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -923,8 +923,8 @@ country PM: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country PR: DFS-FCC (2402 - 2472 @ 40), (30) @@ -937,8 +937,8 @@ country PT: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -973,8 +973,8 @@ country RO: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -984,8 +984,8 @@ country RS: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1014,8 +1014,8 @@ country SE: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1030,8 +1030,8 @@ country SI: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1039,8 +1039,8 @@ country SK: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1097,8 +1097,8 @@ country TR: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR @@ -1181,8 +1181,8 @@ country VC: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5725 - 5875 @ 80), (14) + (5490 - 5730 @ 160), (30), DFS + (5735 - 5875 @ 80), (14) country VE: DFS-FCC (2402 - 2482 @ 40), (30) From 5be6f8fabe68a19d85f46467a14f25f618ebd389 Mon Sep 17 00:00:00 2001 From: Deeraj Soman Date: Fri, 19 Jan 2018 15:57:55 +0530 Subject: [PATCH 067/392] ASoC: msm: Add machine driver support for 32bit capture Add machine driver support for 32bit capture. Change-Id: I9974c4e1a752cce566bb78216b9a9d4e12666341 Signed-off-by: Deeraj Soman Signed-off-by: Dhanalakshmi Siddani --- sound/soc/msm/apq8009-i2s-ext-codec.c | 14 ++++++++++++-- sound/soc/msm/msm8952-slimbus.c | 11 +++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/sound/soc/msm/apq8009-i2s-ext-codec.c b/sound/soc/msm/apq8009-i2s-ext-codec.c index b29273083ba9..bc98deb18efb 100644 --- a/sound/soc/msm/apq8009-i2s-ext-codec.c +++ b/sound/soc/msm/apq8009-i2s-ext-codec.c @@ -325,7 +325,8 @@ static struct snd_soc_dapm_route wcd9335_audio_paths[] = { {"MIC BIAS4", NULL, "MCLK"}, }; -static char const *rx_bit_format_text[] = {"S16_LE", "S24_3LE", "S24_LE"}; +static char const *rx_bit_format_text[] = {"S16_LE", "S24_3LE", "S24_LE", + "S32_LE"}; static const char *const mi2s_tx_ch_text[] = {"One", "Two", "Three", "Four"}; static char const *pri_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", "KHZ_192", "KHZ_8", @@ -633,6 +634,10 @@ static int mi2s_tx_bit_format_get(struct snd_kcontrol *kcontrol, { switch (mi2s_tx_bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + case SNDRV_PCM_FORMAT_S24_LE: ucontrol->value.integer.value[0] = 2; break; @@ -658,6 +663,10 @@ static int mi2s_tx_bit_format_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { switch (ucontrol->value.integer.value[0]) { + case 3: + mi2s_tx_bit_format = SNDRV_PCM_FORMAT_S32_LE; + tx_bits_per_sample = 32; + break; case 2: mi2s_tx_bit_format = SNDRV_PCM_FORMAT_S24_LE; tx_bits_per_sample = 32; @@ -1209,7 +1218,8 @@ static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol, } static const struct soc_enum msm_snd_enum[] = { - SOC_ENUM_SINGLE_EXT(3, rx_bit_format_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_bit_format_text), + rx_bit_format_text), SOC_ENUM_SINGLE_EXT(4, mi2s_tx_ch_text), SOC_ENUM_SINGLE_EXT(6, pri_rx_sample_rate_text), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_ch_text), diff --git a/sound/soc/msm/msm8952-slimbus.c b/sound/soc/msm/msm8952-slimbus.c index 7fccff15cac3..775328a8635a 100644 --- a/sound/soc/msm/msm8952-slimbus.c +++ b/sound/soc/msm/msm8952-slimbus.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1042,6 +1042,9 @@ static int slim0_tx_bit_format_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { switch (slim0_tx_bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; case SNDRV_PCM_FORMAT_S24_3LE: ucontrol->value.integer.value[0] = 2; break; @@ -1065,6 +1068,9 @@ static int slim0_tx_bit_format_put(struct snd_kcontrol *kcontrol, int rc = 0; switch (ucontrol->value.integer.value[0]) { + case 3: + slim0_tx_bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; case 2: slim0_tx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; break; @@ -1799,7 +1805,8 @@ static const char *const slim4_tx_ch_text[] = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; static const char *const vi_feed_ch_text[] = {"One", "Two"}; -static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; +static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE", + "S32_LE"}; static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", "KHZ_192", "KHZ_44P1", "KHZ_16"}; static char const *slim4_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", From 9f571ad5f20396556a29fac47c92b4a4f3897485 Mon Sep 17 00:00:00 2001 From: Balachandra C S Date: Tue, 17 Jul 2018 16:45:26 +0530 Subject: [PATCH 068/392] ARM: dts: msm: Add proper irq type in device tree for mdm device Use proper irq type from gpio interrupt for k61 controller in k61 driver. This interrut type may vary among different targets. Change-Id: I976ebb69c11ab35f4aa904d840482a7e0467459b Signed-off-by: Balachandra C S --- arch/arm/boot/dts/qcom/mdm9650-ttp.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/mdm9650-ttp.dts b/arch/arm/boot/dts/qcom/mdm9650-ttp.dts index 8a951ffb004f..1638d1866ded 100644 --- a/arch/arm/boot/dts/qcom/mdm9650-ttp.dts +++ b/arch/arm/boot/dts/qcom/mdm9650-ttp.dts @@ -78,7 +78,7 @@ spi-max-frequency = <4800000>; reg = <0>; interrupt-parent = <&tlmm_pinmux>; - interrupts = <84 0>; + interrupts = <84 1>; reset-gpio = <&tlmm_pinmux 68 0x1>; pinctrl-names = "active", "sleep"; pinctrl-0 = <&can_rst_on>; From f43ea7d5df8dca22afa49c0940e7e6afdf10da2f Mon Sep 17 00:00:00 2001 From: Ramjee Singh Date: Thu, 17 May 2018 19:25:51 +0530 Subject: [PATCH 069/392] ASoC: msm: Add support for AVS version check Updating pcm and compress driver to use asm read and write apis based on AVS version. Signed-off-by: Soumya Managoli Change-Id: Iec75114fed3a18f054074348d060726f013359cd Signed-off-by: Dhanalakshmi Siddani --- sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c | 57 +++++++++++++- sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 88 ++++++++++++++++++---- 2 files changed, 128 insertions(+), 17 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index f74582035a24..669c99b99e65 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -841,7 +841,20 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, sample_word_size = 16; break; } - ret = q6asm_media_format_block_pcm_format_support_v4( + + switch (q6core_get_avs_version()) { + case (Q6_SUBSYS_AVS2_7): + ret = q6asm_media_format_block_pcm_format_support_v3( + prtd->audio_client, + prtd->sample_rate, + prtd->num_channels, + bit_width, stream_id, + use_default_chmap, + chmap, + sample_word_size); + break; + case (Q6_SUBSYS_AVS2_8): + ret = q6asm_media_format_block_pcm_format_support_v4( prtd->audio_client, prtd->sample_rate, prtd->num_channels, @@ -851,6 +864,12 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, sample_word_size, ASM_LITTLE_ENDIAN, DEFAULT_QF); + break; + case (Q6_SUBSYS_INVALID): + default: + pr_err("%s: INVALID AVS IMAGE\n", __func__); + break; + } if (ret < 0) pr_err("%s: CMD Format block failed\n", __func__); @@ -1118,10 +1137,25 @@ static int msm_compr_configure_dsp_for_playback } else { pr_debug("%s: stream_id %d bits_per_sample %d\n", __func__, ac->stream_id, bits_per_sample); - ret = q6asm_stream_open_write_v4(ac, + + switch (q6core_get_avs_version()) { + case (Q6_SUBSYS_AVS2_7): + ret = q6asm_stream_open_write_v3(ac, prtd->codec, bits_per_sample, ac->stream_id, prtd->gapless_state.use_dsp_gapless_mode); + break; + case (Q6_SUBSYS_AVS2_8): + ret = q6asm_stream_open_write_v4(ac, + prtd->codec, bits_per_sample, + ac->stream_id, + prtd->gapless_state.use_dsp_gapless_mode); + break; + case (Q6_SUBSYS_INVALID): + default: + pr_err("%s: INVALID AVS IMAGE\n", __func__); + break; + } if (ret < 0) { pr_err("%s:ASM open write err[%d] for compr type[%d]\n", __func__, ret, prtd->compr_passthr); @@ -2340,10 +2374,25 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) pr_debug("%s: open_write stream_id %d bits_per_sample %d", __func__, stream_id, bits_per_sample); - rc = q6asm_stream_open_write_v4(prtd->audio_client, + + switch (q6core_get_avs_version()) { + case (Q6_SUBSYS_AVS2_7): + rc = q6asm_stream_open_write_v3(ac, prtd->codec, bits_per_sample, - stream_id, + ac->stream_id, prtd->gapless_state.use_dsp_gapless_mode); + break; + case (Q6_SUBSYS_AVS2_8): + rc = q6asm_stream_open_write_v4(ac, + prtd->codec, bits_per_sample, + ac->stream_id, + prtd->gapless_state.use_dsp_gapless_mode); + break; + case (Q6_SUBSYS_INVALID): + default: + pr_err("%s: INVALID AVS IMAGE\n", __func__); + break; + } if (rc < 0) { pr_err("%s: Session out open failed for gapless\n", __func__); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 8f4961feb604..d3f950d95655 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "msm-pcm-q6-v2.h" #include "msm-pcm-routing-v2.h" @@ -342,9 +343,20 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) break; } - ret = q6asm_open_write_v4(prtd->audio_client, - FORMAT_LINEAR_PCM, bits_per_sample); - + switch (q6core_get_avs_version()) { + case (Q6_SUBSYS_AVS2_7): + ret = q6asm_open_write_v3(prtd->audio_client, + FORMAT_LINEAR_PCM, bits_per_sample); + break; + case (Q6_SUBSYS_AVS2_8): + ret = q6asm_open_write_v4(prtd->audio_client, + FORMAT_LINEAR_PCM, bits_per_sample); + break; + case (Q6_SUBSYS_INVALID): + default: + pr_err("%s: INVALID AVS IMAGE\n", __func__); + break; + } if (ret < 0) { pr_err("%s: q6asm_open_write_v2 failed\n", __func__); q6asm_audio_client_free(prtd->audio_client); @@ -367,12 +379,28 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) return ret; } - ret = q6asm_media_format_block_multi_ch_pcm_v4( + switch (q6core_get_avs_version()) { + case (Q6_SUBSYS_AVS2_7): + ret = q6asm_media_format_block_multi_ch_pcm_v3( + prtd->audio_client, runtime->rate, + runtime->channels, !prtd->set_channel_map, + prtd->channel_map, bits_per_sample, + sample_word_size); + break; + case (Q6_SUBSYS_AVS2_8): + ret = q6asm_media_format_block_multi_ch_pcm_v4( prtd->audio_client, runtime->rate, runtime->channels, !prtd->set_channel_map, prtd->channel_map, bits_per_sample, sample_word_size, ASM_LITTLE_ENDIAN, DEFAULT_QF); + + break; + case (Q6_SUBSYS_INVALID): + default: + pr_err("%s: INVALID AVS IMAGE\n", __func__); + break; + } if (ret < 0) pr_info("%s: CMD Format block failed\n", __func__); @@ -430,8 +458,23 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) __func__, params_channels(params), prtd->audio_client->perf_mode); - ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM, - bits_per_sample); + switch (q6core_get_avs_version()) { + case (Q6_SUBSYS_AVS2_7): + ret = q6asm_open_read_v3(prtd->audio_client, + FORMAT_LINEAR_PCM, + bits_per_sample); + break; + case (Q6_SUBSYS_AVS2_8): + ret = q6asm_open_read_v4(prtd->audio_client, + FORMAT_LINEAR_PCM, + bits_per_sample); + + break; + case (Q6_SUBSYS_INVALID): + default: + pr_err("%s: INVALID AVS IMAGE\n", __func__); + break; + } if (ret < 0) { pr_err("%s: q6asm_open_read failed\n", __func__); q6asm_audio_client_free(prtd->audio_client); @@ -498,13 +541,32 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) pr_debug("%s: Samp_rate = %d Channel = %d bit width = %d, word size = %d\n", __func__, prtd->samp_rate, prtd->channel_mode, bits_per_sample, sample_word_size); - ret = q6asm_enc_cfg_blk_pcm_format_support_v4(prtd->audio_client, - prtd->samp_rate, - prtd->channel_mode, - bits_per_sample, - sample_word_size, - ASM_LITTLE_ENDIAN, - DEFAULT_QF); + + switch (q6core_get_avs_version()) { + case (Q6_SUBSYS_AVS2_7): + ret = q6asm_enc_cfg_blk_pcm_format_support_v3( + prtd->audio_client, + prtd->samp_rate, + prtd->channel_mode, + bits_per_sample, + sample_word_size); + break; + case (Q6_SUBSYS_AVS2_8): + ret = q6asm_enc_cfg_blk_pcm_format_support_v4( + prtd->audio_client, + prtd->samp_rate, + prtd->channel_mode, + bits_per_sample, + sample_word_size, + ASM_LITTLE_ENDIAN, + DEFAULT_QF); + + break; + case (Q6_SUBSYS_INVALID): + default: + pr_err("%s: INVALID AVS IMAGE\n", __func__); + break; + } if (ret < 0) pr_debug("%s: cmd cfg pcm was block failed", __func__); From 116a1e6f86d8996eff03e1d052695d68c169b54d Mon Sep 17 00:00:00 2001 From: Surendar Karka Date: Wed, 2 May 2018 20:02:50 +0530 Subject: [PATCH 070/392] ASoC: msm: qdsp6v2: Add dynamic chmix config support Add support to dynamically configure channel mixing weightage coefficients for ASM sessions. CRs-Fixed: 2235684 Change-Id: Ib184cda4d7f9752d0676c77cb8ff55f65cb30b3c Signed-off-by: Surendar Karka Signed-off-by: Dhanalakshmi Siddani --- include/sound/q6adm-v2.h | 7 +- sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c | 121 +++++++++++++- sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 148 ++++++++++++++++++ sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h | 1 + sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 77 ++++++++- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h | 6 +- sound/soc/msm/qdsp6v2/q6adm.c | 174 +++++++++++---------- 7 files changed, 448 insertions(+), 86 deletions(-) diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h index 7d0f08fcb956..2b75bd4a60e4 100644 --- a/include/sound/q6adm-v2.h +++ b/include/sound/q6adm-v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,6 +28,8 @@ #define AUD_VOL_BLOCK_SIZE 4096 #define AUDIO_RX_CALIBRATION_SIZE (AUD_PROC_BLOCK_SIZE + \ AUD_VOL_BLOCK_SIZE) +#define SESSION_TYPE_RX 0 +#define SESSION_TYPE_TX 1 enum { ADM_CUSTOM_TOP_CAL = 0, ADM_AUDPROC_CAL, @@ -180,5 +182,6 @@ int adm_get_source_tracking(int port_id, int copp_idx, int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, int session_type, struct msm_pcm_channel_mixer *ch_mixer, - int channel_index); + int channel_index, bool use_default_chmap, + char *ch_map); #endif /* __Q6_ADM_V2_H__ */ diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index f74582035a24..3128dbd569f0 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -3436,6 +3436,16 @@ static int msm_compr_probe(struct snd_soc_platform *platform) return 0; } +static int msm_compr_chmix_cfg_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 128; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xFFFFFFFF; + return 0; +} + static int msm_compr_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -3754,6 +3764,113 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) return 0; } + +static int msm_compr_chmix_cfg_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct msm_compr_pdata *pdata = (struct msm_compr_pdata *) + snd_soc_component_get_drvdata(comp); + struct snd_compr_stream *cstream = NULL; + struct snd_soc_pcm_runtime *rtd = NULL; + u64 fe_id = kcontrol->private_value; + int ip_channel_cnt, op_channel_cnt; + int i, index = 0; + int ch_coeff[PCM_FORMAT_MAX_NUM_CHANNEL * PCM_FORMAT_MAX_NUM_CHANNEL]; + bool use_default_chmap = true; + char *chmap = NULL; + + pr_debug("%s: fe_id- %llu\n", __func__, fe_id); + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s: Received out of bounds fe_id %llu\n", + __func__, fe_id); + return -EINVAL; + } + cstream = pdata->cstream[fe_id]; + if (!cstream) { + pr_err("%s: stream inactive\n", __func__); + return -EINVAL; + } + rtd = cstream->private_data; + if (!rtd) { + pr_err("%s: stream inactive\n", __func__); + return -EINVAL; + } + + use_default_chmap = !(pdata->ch_map[rtd->dai_link->be_id]->set_ch_map); + chmap = pdata->ch_map[rtd->dai_link->be_id]->channel_map; + + ip_channel_cnt = ucontrol->value.integer.value[index++]; + op_channel_cnt = ucontrol->value.integer.value[index++]; + /* + * wght coeff of first out channel corresponding to each in channel + * are sent followed by second out channel for each in channel etc. + */ + memset(ch_coeff, 0, sizeof(ch_coeff)); + for (i = 0; i < op_channel_cnt * ip_channel_cnt; i++) { + ch_coeff[i] = + ucontrol->value.integer.value[index++]; + } + + msm_pcm_routing_send_chmix_cfg(fe_id, ip_channel_cnt, op_channel_cnt, + ch_coeff, SESSION_TYPE_RX, use_default_chmap, chmap); + + return 0; +} + +static int msm_compr_chmix_cfg_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +static int msm_compr_add_chmix_cfg_controls(struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = "Audio Stream"; + const char *deviceNo = "NN"; + const char *suffix = "Channel Mix Cfg"; + int ctl_len; + char *mixer_str = NULL; + struct snd_kcontrol_new chmix_cfg_controls[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_compr_chmix_cfg_ctl_info, + .get = msm_compr_chmix_cfg_ctl_get, + .put = msm_compr_chmix_cfg_ctl_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + return -EINVAL; + } + + pr_debug("%s: added new compr FE with name %s, id %d, cpu dai %s, device no %d\n", + __func__, rtd->dai_link->name, rtd->dai_link->be_id, + rtd->dai_link->cpu_dai_name, rtd->pcm->device); + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 + + strlen(suffix) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) + return -ENOMEM; + + snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name, + rtd->pcm->device, suffix); + + chmix_cfg_controls[0].name = mixer_str; + chmix_cfg_controls[0].private_value = rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s", __func__, mixer_str); + snd_soc_add_platform_controls(rtd->platform, + chmix_cfg_controls, + ARRAY_SIZE(chmix_cfg_controls)); + kfree(mixer_str); + return 0; +} + static int msm_compr_add_channel_map_control(struct snd_soc_pcm_runtime *rtd) { const char *mixer_ctl_name = "Playback Channel Map"; @@ -3784,7 +3901,6 @@ static int msm_compr_add_channel_map_control(struct snd_soc_pcm_runtime *rtd) ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) + 1; mixer_str = kzalloc(ctl_len, GFP_KERNEL); - if (!mixer_str) { pr_err("%s: failed to allocate mixer ctrl str of len %d\n", __func__, ctl_len); @@ -3843,6 +3959,9 @@ static int msm_compr_new(struct snd_soc_pcm_runtime *rtd) if (rc) pr_err("%s: Could not add Compr Channel Map Control\n", __func__); + rc = msm_compr_add_chmix_cfg_controls(rtd); + if (rc) + pr_err("%s: add chmix cfg controls failed:%d\n", __func__, rc); return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 8f4961feb604..90dc4ac1a7c7 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -1563,6 +1563,150 @@ static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd) return 0; } +static int msm_pcm_chmix_cfg_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 128; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xFFFFFFFF; + return 0; +} + +static int msm_pcm_chmix_cfg_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *usr_info = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform; + struct msm_plat_data *pdata; + struct snd_pcm_substream *substream; + struct msm_audio *prtd; + u64 fe_id = kcontrol->private_value; + int ip_channel_cnt, op_channel_cnt; + int i, index = 0, ret = 0; + int ch_coeff[PCM_FORMAT_MAX_NUM_CHANNEL * PCM_FORMAT_MAX_NUM_CHANNEL]; + bool use_default_chmap = true; + char *ch_map = NULL; + + pr_debug("%s: fe_id- %llu\n", __func__, fe_id); + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s: Received out of bounds fe_id %llu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + if (!usr_info) { + pr_err("%s: usr_info is null\n", __func__); + ret = -EINVAL; + goto done; + } + platform = snd_soc_component_to_platform(usr_info); + if (!platform) { + pr_err("%s: platform is null\n", __func__); + ret = -EINVAL; + goto done; + } + pdata = dev_get_drvdata(platform->dev); + if (!pdata) { + pr_err("%s: pdata is null\n", __func__); + ret = -EINVAL; + goto done; + } + substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + + if (!substream) { + pr_err("%s substream not found\n", __func__); + return -ENODEV; + } + if (!substream->runtime) { + pr_err("%s substream runtime not found\n", __func__); + ret = -EINVAL; + goto done; + } + prtd = substream->runtime->private_data; + if (!prtd) { + pr_err("%s: stream inactive\n", __func__); + ret = -EINVAL; + goto done; + } + use_default_chmap = !prtd->set_channel_map; + ch_map = prtd->channel_map; + ip_channel_cnt = ucontrol->value.integer.value[index++]; + op_channel_cnt = ucontrol->value.integer.value[index++]; + /* + * wght coeff of first out channel corresponding to each in channel + * are sent followed by second out channel for each in channel etc. + */ + memset(ch_coeff, 0, sizeof(ch_coeff)); + for (i = 0; i < op_channel_cnt * ip_channel_cnt; i++) { + ch_coeff[i] = + ucontrol->value.integer.value[index++]; + } + + msm_pcm_routing_send_chmix_cfg(fe_id, ip_channel_cnt, op_channel_cnt, + ch_coeff, SESSION_TYPE_RX, use_default_chmap, ch_map); +done: + return ret; +} + +static int msm_pcm_chmix_cfg_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +static int msm_pcm_add_chmix_cfg_controls(struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = "Audio Stream"; + const char *deviceNo = "NN"; + const char *suffix = "Channel Mix Cfg"; + char *mixer_str = NULL; + int ctl_len = 0; + struct msm_plat_data *pdata; + struct snd_kcontrol_new chmix_cfg_controls[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_pcm_chmix_cfg_ctl_info, + .get = msm_pcm_chmix_cfg_ctl_get, + .put = msm_pcm_chmix_cfg_ctl_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s: NULL rtd\n", __func__); + return -EINVAL; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + + strlen(deviceNo) + 1 + strlen(suffix) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) + return -ENOMEM; + + snprintf(mixer_str, ctl_len, "%s %d %s", + mixer_ctl_name, rtd->pcm->device, suffix); + chmix_cfg_controls[0].name = mixer_str; + chmix_cfg_controls[0].private_value = rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + pdata = dev_get_drvdata(rtd->platform->dev); + if (pdata) { + if (!pdata->pcm) + pdata->pcm = rtd->pcm; + snd_soc_add_platform_controls(rtd->platform, + chmix_cfg_controls, + ARRAY_SIZE(chmix_cfg_controls)); + } else { + pr_err("%s: NULL pdata\n", __func__); + return -EINVAL; + } + kfree(mixer_str); + return 0; +} + static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd) { int ret = 0; @@ -1580,6 +1724,10 @@ static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add pcm topology control %d\n", __func__, ret); } + + ret = msm_pcm_add_chmix_cfg_controls(rtd); + if (ret) + pr_err("%s: add chmix cfg controls failed:%d\n", __func__, ret); return ret; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h index a5df7f4f5281..b3a7e856a9c0 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h @@ -124,6 +124,7 @@ struct output_meta_data_st { struct msm_plat_data { int perf_mode; int perf_mode_set; + struct snd_pcm *pcm; }; #endif /*_MSM_PCM_H*/ diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 08fca4dbbdc1..13878cab3b4d 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -670,6 +670,78 @@ static bool is_mm_lsm_fe_id(int fe_id) return rc; } +/* + * msm_pcm_routing_send_chmix_cfg + * + * Receives fe_id, ip_channel_cnt, op_channel_cnt, channel weight, session_type + * use_default_chmap and channel map to map in channel mixer and send to + * adm programmable matrix. + * + * fe_id - Passed value, frontend id which is wanted + * ip_channel_cnt - Passed value, number of input channels + * op_channel_cnt - Passed value, number of output channels + * ch_wght_coeff - Passed reference, weights for each output channel + * session_type - Passed value, session_type for RX or TX + * use_default_chmap - true if default channel map to be used + * ch_map - input/output channel map for playback/capture session respectively + */ + +int msm_pcm_routing_send_chmix_cfg(int fe_id, int ip_channel_cnt, + int op_channel_cnt, int *ch_wght_coeff, + int session_type, bool use_default_chmap, + char *channel_map) +{ + int rc = 0, idx = 0, i, j; + int be_index = 0, port_id, index = 0; + unsigned int session_id = 0; + + pr_debug("%s: fe_id[%d] ip_ch[%d] op_ch[%d] sess_type [%d]\n", + __func__, fe_id, ip_channel_cnt, op_channel_cnt, session_type); + + if (!use_default_chmap && (channel_map == NULL)) { + pr_err("%s: No valid chan map and can't use default\n", + __func__); + return -EINVAL; + } + + if ((ch_wght_coeff == NULL) || (op_channel_cnt > ADM_MAX_CHANNELS) || + (ip_channel_cnt > ADM_MAX_CHANNELS)) { + pr_err("%s: Invalid channels or null coefficients\n", __func__); + return -EINVAL; + } + + for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) { + port_id = msm_bedais[be_index].port_id; + if (!msm_bedais[be_index].active || + !test_bit(fe_id, &msm_bedais[be_index].fe_sessions)) + continue; + + session_id = fe_dai_map[fe_id][session_type].strm_id; + channel_mixer[fe_id].input_channels[0] = ip_channel_cnt; + channel_mixer[fe_id].output_channel = op_channel_cnt; + channel_mixer[fe_id].rule = 0; + + for (j = 0; j < op_channel_cnt; j++) { + for (i = 0; i < ip_channel_cnt; i++) + channel_mixer[fe_id].channel_weight[j][i] = + ch_wght_coeff[index++]; + } + for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) { + unsigned long copp = + session_copp_map[fe_id][session_type][be_index]; + if (!test_bit(idx, &copp)) + continue; + rc = adm_programable_channel_mixer(port_id, + idx, session_id, session_type, + channel_mixer + fe_id, 0, + use_default_chmap, channel_map); + if (rc < 0) + pr_err("%s: err setting channel mix config\n", + __func__); + } + } + return 0; +} void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type, int acdb_dev_id, int sample_rate, int session_type) @@ -1127,6 +1199,8 @@ static int msm_pcm_routing_channel_mixer(int fe_id, bool perf_mode, int sess_type = 0; int i = 0, j = 0, be_id; int ret = 0; + bool use_default_chmap = true; + char *ch_map = NULL; if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) { pr_err("%s: invalid FE %d\n", __func__, fe_id); @@ -1169,7 +1243,8 @@ static int msm_pcm_routing_channel_mixer(int fe_id, bool perf_mode, ret = adm_programable_channel_mixer( msm_bedais[be_id].port_id, copp_idx, dspst_id, sess_type, - channel_mixer + fe_id, i); + channel_mixer + fe_id, i, + use_default_chmap, ch_map); } } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index a47377ab38d3..65cdf43c0f71 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -414,4 +414,8 @@ void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type, int acdb_dev_id, int sample_rate, int session_type); int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type, int *app_type, int *acdb_dev_id, int *sample_rate); +int msm_pcm_routing_send_chmix_cfg(int fe_id, int ip_channel_cnt, + int op_channel_cnt, int *ch_wght_coeff, + int session_type, bool use_default_chmap, + char *channel_map); #endif /*_MSM_PCM_H*/ diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c index f1917e703d89..0536e05fb539 100644 --- a/sound/soc/msm/qdsp6v2/q6adm.c +++ b/sound/soc/msm/qdsp6v2/q6adm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -563,18 +563,21 @@ static int adm_populate_channel_weight(u16 *ptr, * session_type - Passed value, session_type for RX or TX * ch_mixer - Passed value, ch_mixer for which channel mixer config is needed * channel_index - Passed value, channel_index for which channel is needed + * use_default_chmap - true if default channel map to be used + * ch_map - input/output channel map for playback/capture session respectively */ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, int session_type, struct msm_pcm_channel_mixer *ch_mixer, - int channel_index) + int channel_index, bool use_default_chmap, + char *ch_map) { struct adm_cmd_set_pspd_mtmx_strtr_params_v5 *adm_params = NULL; struct adm_param_data_v5 data_v5; int ret = 0, port_idx, sz = 0, param_size = 0; u16 *adm_pspd_params; u16 *ptr; - int index = 0; + int index = 0, i; pr_debug("%s: port_id = %d\n", __func__, port_id); port_id = afe_convert_virtual_to_portid(port_id); @@ -641,84 +644,93 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id, adm_pspd_params[3] = ch_mixer->input_channels[channel_index]; index = 4; - if (ch_mixer->output_channel == 1) { - adm_pspd_params[index] = PCM_CHANNEL_FC; - } else if (ch_mixer->output_channel == 2) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - } else if (ch_mixer->output_channel == 3) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - adm_pspd_params[index + 2] = PCM_CHANNEL_FC; - } else if (ch_mixer->output_channel == 4) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - adm_pspd_params[index + 2] = PCM_CHANNEL_LS; - adm_pspd_params[index + 3] = PCM_CHANNEL_RS; - } else if (ch_mixer->output_channel == 5) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - adm_pspd_params[index + 2] = PCM_CHANNEL_FC; - adm_pspd_params[index + 3] = PCM_CHANNEL_LS; - adm_pspd_params[index + 4] = PCM_CHANNEL_RS; - } else if (ch_mixer->output_channel == 6) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; - adm_pspd_params[index + 3] = PCM_CHANNEL_FC; - adm_pspd_params[index + 4] = PCM_CHANNEL_LS; - adm_pspd_params[index + 5] = PCM_CHANNEL_RS; - } else if (ch_mixer->output_channel == 8) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; - adm_pspd_params[index + 3] = PCM_CHANNEL_FC; - adm_pspd_params[index + 4] = PCM_CHANNEL_LS; - adm_pspd_params[index + 5] = PCM_CHANNEL_RS; - adm_pspd_params[index + 6] = PCM_CHANNEL_LB; - adm_pspd_params[index + 7] = PCM_CHANNEL_RB; - } - - index = index + ch_mixer->output_channel; - if (ch_mixer->input_channels[channel_index] == 1) { - adm_pspd_params[index] = PCM_CHANNEL_FC; - } else if (ch_mixer->input_channels[channel_index] == 2) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - } else if (ch_mixer->input_channels[channel_index] == 3) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - adm_pspd_params[index + 2] = PCM_CHANNEL_FC; - } else if (ch_mixer->input_channels[channel_index] == 4) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - adm_pspd_params[index + 2] = PCM_CHANNEL_LS; - adm_pspd_params[index + 3] = PCM_CHANNEL_RS; - } else if (ch_mixer->input_channels[channel_index] == 5) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - adm_pspd_params[index + 2] = PCM_CHANNEL_FC; - adm_pspd_params[index + 3] = PCM_CHANNEL_LS; - adm_pspd_params[index + 4] = PCM_CHANNEL_RS; - } else if (ch_mixer->input_channels[channel_index] == 6) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; - adm_pspd_params[index + 3] = PCM_CHANNEL_FC; - adm_pspd_params[index + 4] = PCM_CHANNEL_LS; - adm_pspd_params[index + 5] = PCM_CHANNEL_RS; - } else if (ch_mixer->input_channels[channel_index] == 8) { - adm_pspd_params[index] = PCM_CHANNEL_FL; - adm_pspd_params[index + 1] = PCM_CHANNEL_FR; - adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; - adm_pspd_params[index + 3] = PCM_CHANNEL_FC; - adm_pspd_params[index + 4] = PCM_CHANNEL_LS; - adm_pspd_params[index + 5] = PCM_CHANNEL_RS; - adm_pspd_params[index + 6] = PCM_CHANNEL_LB; - adm_pspd_params[index + 7] = PCM_CHANNEL_RB; - } - - index = index + ch_mixer->input_channels[channel_index]; + if ((session_type == SESSION_TYPE_TX) && !use_default_chmap && ch_map) { + for (i = 0; i < ch_mixer->output_channel; i++) + adm_pspd_params[index++] = ch_map[i]; + } else { + if (ch_mixer->output_channel == 1) { + adm_pspd_params[index] = PCM_CHANNEL_FC; + } else if (ch_mixer->output_channel == 2) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + } else if (ch_mixer->output_channel == 3) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_FC; + } else if (ch_mixer->output_channel == 4) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LS; + adm_pspd_params[index + 3] = PCM_CHANNEL_RS; + } else if (ch_mixer->output_channel == 5) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_FC; + adm_pspd_params[index + 3] = PCM_CHANNEL_LS; + adm_pspd_params[index + 4] = PCM_CHANNEL_RS; + } else if (ch_mixer->output_channel == 6) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; + adm_pspd_params[index + 3] = PCM_CHANNEL_FC; + adm_pspd_params[index + 4] = PCM_CHANNEL_LS; + adm_pspd_params[index + 5] = PCM_CHANNEL_RS; + } else if (ch_mixer->output_channel == 8) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; + adm_pspd_params[index + 3] = PCM_CHANNEL_FC; + adm_pspd_params[index + 4] = PCM_CHANNEL_LS; + adm_pspd_params[index + 5] = PCM_CHANNEL_RS; + adm_pspd_params[index + 6] = PCM_CHANNEL_LB; + adm_pspd_params[index + 7] = PCM_CHANNEL_RB; + } + index = index + ch_mixer->output_channel; + } + + if ((session_type == SESSION_TYPE_RX) && !use_default_chmap && ch_map) { + for (i = 0; i < ch_mixer->input_channels[channel_index]; i++) + adm_pspd_params[index++] = ch_map[i]; + } else { + if (ch_mixer->input_channels[channel_index] == 1) { + adm_pspd_params[index] = PCM_CHANNEL_FC; + } else if (ch_mixer->input_channels[channel_index] == 2) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + } else if (ch_mixer->input_channels[channel_index] == 3) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_FC; + } else if (ch_mixer->input_channels[channel_index] == 4) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LS; + adm_pspd_params[index + 3] = PCM_CHANNEL_RS; + } else if (ch_mixer->input_channels[channel_index] == 5) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_FC; + adm_pspd_params[index + 3] = PCM_CHANNEL_LS; + adm_pspd_params[index + 4] = PCM_CHANNEL_RS; + } else if (ch_mixer->input_channels[channel_index] == 6) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; + adm_pspd_params[index + 3] = PCM_CHANNEL_FC; + adm_pspd_params[index + 4] = PCM_CHANNEL_LS; + adm_pspd_params[index + 5] = PCM_CHANNEL_RS; + } else if (ch_mixer->input_channels[channel_index] == 8) { + adm_pspd_params[index] = PCM_CHANNEL_FL; + adm_pspd_params[index + 1] = PCM_CHANNEL_FR; + adm_pspd_params[index + 2] = PCM_CHANNEL_LFE; + adm_pspd_params[index + 3] = PCM_CHANNEL_FC; + adm_pspd_params[index + 4] = PCM_CHANNEL_LS; + adm_pspd_params[index + 5] = PCM_CHANNEL_RS; + adm_pspd_params[index + 6] = PCM_CHANNEL_LB; + adm_pspd_params[index + 7] = PCM_CHANNEL_RB; + } + index = index + ch_mixer->input_channels[channel_index]; + } ret = adm_populate_channel_weight(&adm_pspd_params[index], ch_mixer, channel_index); if (!ret) { From 815a9a9a3c320ac204ff58b49fde697216ebf88a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 2 Nov 2017 00:47:19 +0000 Subject: [PATCH 071/392] KEYS: fix out-of-bounds read during ASN.1 parsing commit 2eb9eabf1e868fda15808954fb29b0f105ed65f1 upstream. syzkaller with KASAN reported an out-of-bounds read in asn1_ber_decoder(). It can be reproduced by the following command, assuming CONFIG_X509_CERTIFICATE_PARSER=y and CONFIG_KASAN=y: keyctl add asymmetric desc $'\x30\x30' @s The bug is that the length of an ASN.1 data value isn't validated in the case where it is encoded using the short form, causing the decoder to read past the end of the input buffer. Fix it by validating the length. The bug report was: BUG: KASAN: slab-out-of-bounds in asn1_ber_decoder+0x10cb/0x1730 lib/asn1_decoder.c:233 Read of size 1 at addr ffff88003cccfa02 by task syz-executor0/6818 CPU: 1 PID: 6818 Comm: syz-executor0 Not tainted 4.14.0-rc7-00008-g5f479447d983 #2 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:16 [inline] dump_stack+0xb3/0x10b lib/dump_stack.c:52 print_address_description+0x79/0x2a0 mm/kasan/report.c:252 kasan_report_error mm/kasan/report.c:351 [inline] kasan_report+0x236/0x340 mm/kasan/report.c:409 __asan_report_load1_noabort+0x14/0x20 mm/kasan/report.c:427 asn1_ber_decoder+0x10cb/0x1730 lib/asn1_decoder.c:233 x509_cert_parse+0x1db/0x650 crypto/asymmetric_keys/x509_cert_parser.c:89 x509_key_preparse+0x64/0x7a0 crypto/asymmetric_keys/x509_public_key.c:174 asymmetric_key_preparse+0xcb/0x1a0 crypto/asymmetric_keys/asymmetric_type.c:388 key_create_or_update+0x347/0xb20 security/keys/key.c:855 SYSC_add_key security/keys/keyctl.c:122 [inline] SyS_add_key+0x1cd/0x340 security/keys/keyctl.c:62 entry_SYSCALL_64_fastpath+0x1f/0xbe RIP: 0033:0x447c89 RSP: 002b:00007fca7a5d3bd8 EFLAGS: 00000246 ORIG_RAX: 00000000000000f8 RAX: ffffffffffffffda RBX: 00007fca7a5d46cc RCX: 0000000000447c89 RDX: 0000000020006f4a RSI: 0000000020006000 RDI: 0000000020001ff5 RBP: 0000000000000046 R08: fffffffffffffffd R09: 0000000000000000 R10: 0000000000000002 R11: 0000000000000246 R12: 0000000000000000 R13: 0000000000000000 R14: 00007fca7a5d49c0 R15: 00007fca7a5d4700 Fixes: 42d5ec27f873 ("X.509: Add an ASN.1 decoder") Bug: 73827422 Signed-off-by: Eric Biggers Signed-off-by: David Howells Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman Change-Id: Ic3610c239a719762d5b337c3fff670a8aa581069 Git-repo: https://android.googlesource.com/kernel/msm Git-commit: f4d43291da8a3db89c7d9597beb782775c623d3c Signed-off-by: Srinivasa Rao Kuppala --- lib/asn1_decoder.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c index 806c5b6b4b3a..828ead6b78a8 100644 --- a/lib/asn1_decoder.c +++ b/lib/asn1_decoder.c @@ -276,6 +276,9 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, if (unlikely(len > datalen - dp)) goto data_overrun_error; } + } else { + if (unlikely(len > datalen - dp)) + goto data_overrun_error; } if (flags & FLAG_CONS) { From b3eecacdb8fe0b38ccf81f9545a1b84d3378af9b Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Wed, 18 Jul 2018 20:13:25 +0530 Subject: [PATCH 072/392] ASoC: msm: Add new dai links for compress capture for apq8009 Add new dai links to add support for compress capture on external codec for apq8009 and add capture support for a dai link. CRs-Fixed: 2273335 Change-Id: I9357a2a3d49a9df261d4528a1dde5f635a1b1eda Signed-off-by: Dhanalakshmi Siddani --- sound/soc/msm/apq8009-i2s-ext-codec.c | 55 +++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/sound/soc/msm/apq8009-i2s-ext-codec.c b/sound/soc/msm/apq8009-i2s-ext-codec.c index bc98deb18efb..14734a366096 100644 --- a/sound/soc/msm/apq8009-i2s-ext-codec.c +++ b/sound/soc/msm/apq8009-i2s-ext-codec.c @@ -2111,6 +2111,7 @@ static struct snd_soc_dai_link apq8009_dai[] = { .platform_name = "msm-compress-dsp", .dynamic = 1, .dpcm_playback = 1, + .dpcm_capture = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .codec_dai_name = "snd-soc-dummy-dai", @@ -2390,6 +2391,40 @@ static struct snd_soc_dai_link msm_tdm_fe_dai[] = { }, }; +static struct snd_soc_dai_link msm_compr_fe_dai[] = { + /* FE TDM DAI links */ + {/* hw:x,43 */ + .name = "APQ8009 Compress3", + .stream_name = "Compress3", + .cpu_dai_name = "MultiMedia10", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA10, + }, + {/* hw:x,44 */ + .name = "APQ8009 Compress4", + .stream_name = "Compress4", + .cpu_dai_name = "MultiMedia11", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA11, + }, +}; + static struct snd_soc_dai_link msm_tdm_be_dai[] = { /* TDM be dai links */ { @@ -2425,6 +2460,7 @@ static struct snd_soc_dai_link msm_tdm_be_dai[] = { static struct snd_soc_dai_link apq8009_9326_dai_links[ ARRAY_SIZE(apq8009_dai) + ARRAY_SIZE(msm_tdm_fe_dai) + + ARRAY_SIZE(msm_compr_fe_dai) + ARRAY_SIZE(apq8009_9326_dai) + ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link) + ARRAY_SIZE(msm_tdm_be_dai)]; @@ -2447,7 +2483,7 @@ static int populate_ext_snd_card_dt_data(struct platform_device *pdev) struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) { struct snd_soc_card *card = &snd_soc_card_9326_apq8009; - int ret, len1, len2, len3; + int ret, len1, len2, len3, len4; card->dev = dev; ret = snd_soc_of_parse_card_name(card, "qcom,model"); @@ -2460,34 +2496,37 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) len1 = ARRAY_SIZE(apq8009_dai); len2 = len1 + ARRAY_SIZE(msm_tdm_fe_dai); - len3 = len2 + ARRAY_SIZE(apq8009_9326_dai); + len3 = len2 + ARRAY_SIZE(msm_compr_fe_dai); + len4 = len3 + ARRAY_SIZE(apq8009_9326_dai); memcpy(apq8009_9326_dai_links, apq8009_dai, sizeof(apq8009_dai)); memcpy(apq8009_9326_dai_links + len1, msm_tdm_fe_dai, sizeof(msm_tdm_fe_dai)); - memcpy(apq8009_9326_dai_links + len2, apq8009_9326_dai, + memcpy(apq8009_9326_dai_links + len2, msm_compr_fe_dai, + sizeof(msm_compr_fe_dai)); + memcpy(apq8009_9326_dai_links + len3, apq8009_9326_dai, sizeof(apq8009_9326_dai)); if (of_property_read_bool(dev->of_node, "qcom,afe-rxtx-lb")) { dev_dbg(dev, "%s(): AFE RX to TX loopback supported\n", __func__); - memcpy(apq8009_9326_dai_links + len3, + memcpy(apq8009_9326_dai_links + len4, msm_afe_rxtx_lb_be_dai_link, sizeof(msm_afe_rxtx_lb_be_dai_link)); - len3 += ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link); + len4 += ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link); } if (of_property_read_bool(dev->of_node, "qcom,tdm-audio-intf")) { dev_dbg(dev, "%s(): TDM support present\n", __func__); - memcpy(apq8009_9326_dai_links + len3, msm_tdm_be_dai, + memcpy(apq8009_9326_dai_links + len4, msm_tdm_be_dai, sizeof(msm_tdm_be_dai)); - len3 += ARRAY_SIZE(msm_tdm_be_dai); + len4 += ARRAY_SIZE(msm_tdm_be_dai); } card->dai_link = apq8009_9326_dai_links; - card->num_links = len3; + card->num_links = len4; card->dev = dev; return card; From 94ae70c28e3894fa067f1c88ec79802b66c939bf Mon Sep 17 00:00:00 2001 From: Vijay Navnath Kamble Date: Mon, 23 Jul 2018 11:33:16 +0530 Subject: [PATCH 073/392] defconfig: msm: enable new touch driver compilation Add support for compiling of new himax touch driver. Change-Id: I1433c10b8968d1e9322cd42147cc95f177ed1b34 Signed-off-by: Vijay Navnath Kamble --- arch/arm/configs/msmcortex-perf_defconfig | 4 ++++ arch/arm/configs/msmcortex_defconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm/configs/msmcortex-perf_defconfig b/arch/arm/configs/msmcortex-perf_defconfig index 0152945efdc6..378119e357a0 100644 --- a/arch/arm/configs/msmcortex-perf_defconfig +++ b/arch/arm/configs/msmcortex-perf_defconfig @@ -307,6 +307,10 @@ CONFIG_TOUCHSCREEN_ATMEL_MXT=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_MAXIM_STI=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_KEYCHORD=y diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig index cb620619749a..4e6b91757b5f 100644 --- a/arch/arm/configs/msmcortex_defconfig +++ b/arch/arm/configs/msmcortex_defconfig @@ -307,6 +307,10 @@ CONFIG_SECURE_TOUCH=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_MAXIM_STI=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_UINPUT=y From 32509d05b90a241f3cb7f9bb8f387f1712c03e50 Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Tue, 24 Apr 2018 09:54:50 +0530 Subject: [PATCH 074/392] ARM: dts: msm: Untrusted pointer dereference To avoid access of variable after being freed, using list_first_entry_safe function to iterate over list of given type, safe against removal of list entry. Change-Id: I70611fddf3e9b80b1affa3e5235be24eac0d0a58 Signed-off-by: Monika Singh --- drivers/misc/qseecom.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index f2955be61899..1fca674d3ed9 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -8648,6 +8648,7 @@ static int qseecom_probe(struct platform_device *pdev) static int qseecom_remove(struct platform_device *pdev) { struct qseecom_registered_kclient_list *kclient = NULL; + struct qseecom_registered_kclient_list *kclient_tmp = NULL; unsigned long flags = 0; int ret = 0; int i; @@ -8657,10 +8658,8 @@ static int qseecom_remove(struct platform_device *pdev) atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_NOT_READY); spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags); - list_for_each_entry(kclient, &qseecom.registered_kclient_list_head, - list) { - if (!kclient) - goto exit_irqrestore; + list_for_each_entry_safe(kclient, kclient_tmp, + &qseecom.registered_kclient_list_head, list) { /* Break the loop if client handle is NULL */ if (!kclient->handle) @@ -8684,7 +8683,7 @@ static int qseecom_remove(struct platform_device *pdev) kzfree(kclient->handle); exit_free_kclient: kzfree(kclient); -exit_irqrestore: + spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags); if (qseecom.qseos_version > QSEEE_VERSION_00) From 61132e8dd29df1f5b177599d6a9fb8fc122a61c1 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 2 Nov 2017 00:47:19 +0000 Subject: [PATCH 075/392] KEYS: fix out-of-bounds read during ASN.1 parsing commit 2eb9eabf1e868fda15808954fb29b0f105ed65f1 upstream. syzkaller with KASAN reported an out-of-bounds read in asn1_ber_decoder(). It can be reproduced by the following command, assuming CONFIG_X509_CERTIFICATE_PARSER=y and CONFIG_KASAN=y: keyctl add asymmetric desc $'\x30\x30' @s The bug is that the length of an ASN.1 data value isn't validated in the case where it is encoded using the short form, causing the decoder to read past the end of the input buffer. Fix it by validating the length. The bug report was: BUG: KASAN: slab-out-of-bounds in asn1_ber_decoder+0x10cb/0x1730 lib/asn1_decoder.c:233 Read of size 1 at addr ffff88003cccfa02 by task syz-executor0/6818 CPU: 1 PID: 6818 Comm: syz-executor0 Not tainted 4.14.0-rc7-00008-g5f479447d983 #2 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:16 [inline] dump_stack+0xb3/0x10b lib/dump_stack.c:52 print_address_description+0x79/0x2a0 mm/kasan/report.c:252 kasan_report_error mm/kasan/report.c:351 [inline] kasan_report+0x236/0x340 mm/kasan/report.c:409 __asan_report_load1_noabort+0x14/0x20 mm/kasan/report.c:427 asn1_ber_decoder+0x10cb/0x1730 lib/asn1_decoder.c:233 x509_cert_parse+0x1db/0x650 crypto/asymmetric_keys/x509_cert_parser.c:89 x509_key_preparse+0x64/0x7a0 crypto/asymmetric_keys/x509_public_key.c:174 asymmetric_key_preparse+0xcb/0x1a0 crypto/asymmetric_keys/asymmetric_type.c:388 key_create_or_update+0x347/0xb20 security/keys/key.c:855 SYSC_add_key security/keys/keyctl.c:122 [inline] SyS_add_key+0x1cd/0x340 security/keys/keyctl.c:62 entry_SYSCALL_64_fastpath+0x1f/0xbe RIP: 0033:0x447c89 RSP: 002b:00007fca7a5d3bd8 EFLAGS: 00000246 ORIG_RAX: 00000000000000f8 RAX: ffffffffffffffda RBX: 00007fca7a5d46cc RCX: 0000000000447c89 RDX: 0000000020006f4a RSI: 0000000020006000 RDI: 0000000020001ff5 RBP: 0000000000000046 R08: fffffffffffffffd R09: 0000000000000000 R10: 0000000000000002 R11: 0000000000000246 R12: 0000000000000000 R13: 0000000000000000 R14: 00007fca7a5d49c0 R15: 00007fca7a5d4700 Fixes: 42d5ec27f873 ("X.509: Add an ASN.1 decoder") Bug: 73827422 Signed-off-by: Eric Biggers Signed-off-by: David Howells Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman Change-Id: Ic3610c239a719762d5b337c3fff670a8aa581069 Git-repo: https://android.googlesource.com/kernel/msm Git-commit: f4d43291da8a3db89c7d9597beb782775c623d3c Signed-off-by: Srinivasa Rao Kuppala --- lib/asn1_decoder.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c index 806c5b6b4b3a..828ead6b78a8 100644 --- a/lib/asn1_decoder.c +++ b/lib/asn1_decoder.c @@ -276,6 +276,9 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, if (unlikely(len > datalen - dp)) goto data_overrun_error; } + } else { + if (unlikely(len > datalen - dp)) + goto data_overrun_error; } if (flags & FLAG_CONS) { From 8cb912acc60e69fbfd26d283b079ed837f0eac8a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 8 Dec 2017 15:13:27 +0000 Subject: [PATCH 076/392] KEYS: add missing permission check for request_key() destination When the request_key() syscall is not passed a destination keyring, it links the requested key (if constructed) into the "default" request-key keyring. This should require Write permission to the keyring. However, there is actually no permission check. This can be abused to add keys to any keyring to which only Search permission is granted. This is because Search permission allows joining the keyring. keyctl_set_reqkey_keyring(KEY_REQKEY_DEFL_SESSION_KEYRING) then will set the default request-key keyring to the session keyring. Then, request_key() can be used to add keys to the keyring. Both negatively and positively instantiated keys can be added using this method. Adding negative keys is trivial. Adding a positive key is a bit trickier. It requires that either /sbin/request-key positively instantiates the key, or that another thread adds the key to the process keyring at just the right time, such that request_key() misses it initially but then finds it in construct_alloc_key(). Fix this bug by checking for Write permission to the keyring in construct_get_dest_keyring() when the default keyring is being used. We don't do the permission check for non-default keyrings because that was already done by the earlier call to lookup_user_key(). Also, request_key_and_link() is currently passed a 'struct key *' rather than a key_ref_t, so the "possessed" bit is unavailable. We also don't do the permission check for the "requestor keyring", to continue to support the use case described by commit 8bbf4976b59f ("KEYS: Alter use of key instantiation link-to-keyring argument") where /sbin/request-key recursively calls request_key() to add keys to the original requestor's destination keyring. (I don't know of any users who actually do that, though...) Change-Id: I3603fec8fab929d7636d7223901f16dc8d8026cc Fixes: 3e30148c3d52 ("[PATCH] Keys: Make request-key create an authorisation key") Cc: # v2.6.13+ Signed-off-by: Eric Biggers Signed-off-by: David Howells Git-commit: 4dca6ea1d9432052afb06baf2e3ae78188a4410b Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Srinivasa Rao Kuppala Signed-off-by: Chetan C R --- security/keys/request_key.c | 49 ++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 0c7aea4dea54..8117a774ee5d 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -250,11 +250,12 @@ static int construct_key(struct key *key, const void *callout_info, * The keyring selected is returned with an extra reference upon it which the * caller must release. */ -static void construct_get_dest_keyring(struct key **_dest_keyring) +static int construct_get_dest_keyring(struct key **_dest_keyring) { struct request_key_auth *rka; const struct cred *cred = current_cred(); struct key *dest_keyring = *_dest_keyring, *authkey; + int ret; kenter("%p", dest_keyring); @@ -263,6 +264,8 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) /* the caller supplied one */ key_get(dest_keyring); } else { + bool do_perm_check = true; + /* use a default keyring; falling through the cases until we * find one that we actually have */ switch (cred->jit_keyring) { @@ -277,8 +280,10 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) dest_keyring = key_get(rka->dest_keyring); up_read(&authkey->sem); - if (dest_keyring) + if (dest_keyring) { + do_perm_check = false; break; + } } case KEY_REQKEY_DEFL_THREAD_KEYRING: @@ -313,11 +318,29 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) default: BUG(); } + + /* + * Require Write permission on the keyring. This is essential + * because the default keyring may be the session keyring, and + * joining a keyring only requires Search permission. + * + * However, this check is skipped for the "requestor keyring" so + * that /sbin/request-key can itself use request_key() to add + * keys to the original requestor's destination keyring. + */ + if (dest_keyring && do_perm_check) { + ret = key_permission(make_key_ref(dest_keyring, 1), + KEY_NEED_WRITE); + if (ret) { + key_put(dest_keyring); + return ret; + } + } } *_dest_keyring = dest_keyring; kleave(" [dk %d]", key_serial(dest_keyring)); - return; + return 0; } /* @@ -439,11 +462,18 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, kenter(""); - user = key_user_lookup(current_fsuid()); - if (!user) - return ERR_PTR(-ENOMEM); + if (ctx->index_key.type == &key_type_keyring) + return ERR_PTR(-EPERM); + + ret = construct_get_dest_keyring(&dest_keyring); + if (ret) + goto error; - construct_get_dest_keyring(&dest_keyring); + user = key_user_lookup(current_fsuid()); + if (!user) { + ret = -ENOMEM; + goto error_put_dest_keyring; + } ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key); key_user_put(user); @@ -458,7 +488,7 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, } else if (ret == -EINPROGRESS) { ret = 0; } else { - goto couldnt_alloc_key; + goto error_put_dest_keyring; } key_put(dest_keyring); @@ -468,8 +498,9 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, construction_failed: key_negate_and_link(key, key_negative_timeout, NULL, NULL); key_put(key); -couldnt_alloc_key: +error_put_dest_keyring: key_put(dest_keyring); +error: kleave(" = %d", ret); return ERR_PTR(ret); } From fd15809871e7d00eb425ef75f967259dfaec3268 Mon Sep 17 00:00:00 2001 From: Rashi Bindra Date: Thu, 19 Jul 2018 12:40:52 +0530 Subject: [PATCH 077/392] msm: mdss: Change function from disbale_irq_nosync to disbale_irq Potential deadlock can happen while we disable irq and at the same time an irq is triggered to request for the same resource. Thus, it will pre-empt the spin-lock. Hence, change the function call to disbale_irq to prevent local interrupts. Change-Id: I7b80810b13660df8801533d418c78f2db75dd5b6 Signed-off-by: Rashi Bindra --- drivers/video/msm/mdss/mdss_dsi_host.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c index 799a4e6ce371..9f28380b151b 100644 --- a/drivers/video/msm/mdss/mdss_dsi_host.c +++ b/drivers/video/msm/mdss/mdss_dsi_host.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2104,7 +2104,7 @@ static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl, /* clear CMD DMA and BTA_DONE isr only */ reg_val |= (DSI_INTR_CMD_DMA_DONE | DSI_INTR_BTA_DONE); MIPI_OUTP(ctrl->ctrl_base + 0x0110, reg_val); - mdss_dsi_disable_irq_nosync(ctrl, DSI_CMD_TERM); + mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); complete(&ctrl->dma_comp); pr_warn("%s: dma tx done but irq not triggered\n", From 00607b0aec5e4b821e036c4da943c39109296a50 Mon Sep 17 00:00:00 2001 From: Vijay Navnath Kamble Date: Wed, 25 Jul 2018 16:43:57 +0530 Subject: [PATCH 078/392] ARM: dts: msm: Delete redundant code in hx83100a LCD Delete the byte streams of dcs packets which are redundant for 8" hx83100a LCD Panel. Change-Id: I0c30001ded45a2fcf65ee49716e5d0a1c6403726 Signed-off-by: Vijay Navnath Kamble --- arch/arm/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi index 9ad11c4cf64d..c5b7575ef438 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi @@ -39,11 +39,6 @@ qcom,mdss-dsi-on-command = [ 39 01 00 00 78 00 02 11 00 39 01 00 00 14 00 02 29 00 - 39 01 00 00 00 00 04 B9 83 10 0A - 39 01 00 00 00 00 08 C9 1F 00 08 1E 81 1E 00 - 39 01 00 00 00 00 02 53 24 - 39 01 00 00 05 00 02 55 02 - 39 01 00 00 00 00 0A CA 40 3C 38 34 33 32 30 2C 28 ]; qcom,mdss-dsi-off-command = [05 01 00 00 96 00 02 28 00 05 01 00 00 00 00 02 10 00]; From 682028dcbed50d3e77bb88831296284cd157a807 Mon Sep 17 00:00:00 2001 From: Lakshmi Narayana Kalavala Date: Tue, 24 Jul 2018 13:35:43 -0700 Subject: [PATCH 079/392] drm/msm: Fix the format prints in display driver Fix the %p format prints with %pK. Change-Id: I1743bacb76c1db4bfa304146f7d391751b35273c Signed-off-by: Lakshmi Narayana Kalavala --- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c | 6 +++--- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 4 ++-- drivers/gpu/drm/msm/dsi-staging/dsi_phy.c | 5 +++-- drivers/gpu/drm/msm/edp/edp.c | 4 ++-- drivers/gpu/drm/msm/msm_drv.c | 13 +++++++------ drivers/gpu/drm/msm/msm_fb.c | 6 +++--- drivers/gpu/drm/msm/msm_fbdev.c | 4 ++-- drivers/gpu/drm/msm/msm_gem.c | 8 ++++---- drivers/gpu/drm/msm/sde/sde_crtc.c | 4 ++-- drivers/gpu/drm/msm/sde/sde_hw_catalog.c | 4 ++-- drivers/gpu/drm/msm/sde/sde_plane.c | 4 ++-- 11 files changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index b8520aadbc0c..c993ae279ca9 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -484,7 +484,7 @@ static int dsi_ctrl_init_regmap(struct platform_device *pdev, } ctrl->hw.base = ptr; - pr_debug("[%s] map dsi_ctrl registers to %p\n", ctrl->name, + pr_debug("[%s] map dsi_ctrl registers to %pK\n", ctrl->name, ctrl->hw.base); ptr = msm_ioremap(pdev, "mmss_misc", ctrl->name); @@ -494,7 +494,7 @@ static int dsi_ctrl_init_regmap(struct platform_device *pdev, } ctrl->hw.mmss_misc_base = ptr; - pr_debug("[%s] map mmss_misc registers to %p\n", ctrl->name, + pr_debug("[%s] map mmss_misc registers to %pK\n", ctrl->name, ctrl->hw.mmss_misc_base); return rc; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 7a8dd567bb1f..1af0a55f840f 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1469,7 +1469,7 @@ static int dsi_panel_parse_dba_config(struct dsi_panel *panel, "qcom,bridge-name", &len); if (!panel->dba_config.bridge_name || len <= 0) { SDE_ERROR( - "%s:%d Unable to read bridge_name, data=%p,len=%d\n", + "%s:%d Unable to read bridge_name, data=%pK,len=%d\n", __func__, __LINE__, panel->dba_config.bridge_name, len); rc = -EINVAL; goto error; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c index 1ccbbe7df573..f7a77336e691 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -93,7 +93,8 @@ static int dsi_phy_regmap_init(struct platform_device *pdev, phy->hw.base = ptr; - pr_debug("[%s] map dsi_phy registers to %p\n", phy->name, phy->hw.base); + pr_debug("[%s] map dsi_phy registers to %pK\n", + phy->name, phy->hw.base); return rc; } diff --git a/drivers/gpu/drm/msm/edp/edp.c b/drivers/gpu/drm/msm/edp/edp.c index 0940e84b2821..253e022ffb09 100644 --- a/drivers/gpu/drm/msm/edp/edp.c +++ b/drivers/gpu/drm/msm/edp/edp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -54,7 +54,7 @@ static struct msm_edp *edp_init(struct platform_device *pdev) ret = -ENOMEM; goto fail; } - DBG("eDP probed=%p", edp); + DBG("eDP probed=%pK", edp); edp->pdev = pdev; platform_set_drvdata(pdev, edp); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 62e3047e3f31..63a1de59c3a5 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -2,7 +2,7 @@ * Copyright (C) 2013 Red Hat * Author: Rob Clark * - * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by @@ -99,7 +99,8 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, } if (reglog) - printk(KERN_DEBUG "IO:region %s %p %08lx\n", dbgname, ptr, size); + pr_debug("IO:region %s %pK %08lx\n", + dbgname, ptr, size); return ptr; } @@ -107,7 +108,7 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, void msm_writel(u32 data, void __iomem *addr) { if (reglog) - printk(KERN_DEBUG "IO:W %p %08x\n", addr, data); + pr_debug("IO:W %pK %08x\n", addr, data); writel(data, addr); } @@ -115,7 +116,7 @@ u32 msm_readl(const void __iomem *addr) { u32 val = readl(addr); if (reglog) - printk(KERN_ERR "IO:R %p %08x\n", addr, val); + pr_debug("IO:R %pK %08x\n", addr, val); return val; } @@ -598,7 +599,7 @@ static int msm_enable_vblank(struct drm_device *dev, unsigned int pipe) struct msm_kms *kms = priv->kms; if (!kms) return -ENXIO; - DBG("dev=%p, crtc=%u", dev, pipe); + DBG("dev=%pK crtc=%u", dev, pipe); return vblank_ctrl_queue_work(priv, pipe, true); } @@ -608,7 +609,7 @@ static void msm_disable_vblank(struct drm_device *dev, unsigned int pipe) struct msm_kms *kms = priv->kms; if (!kms) return; - DBG("dev=%p, crtc=%u", dev, pipe); + DBG("dev=%pK, crtc=%u", dev, pipe); vblank_ctrl_queue_work(priv, pipe, false); } diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index dca4de382581..7b1a6246b268 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -43,7 +43,7 @@ static void msm_framebuffer_destroy(struct drm_framebuffer *fb) struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); int i, n = drm_format_num_planes(fb->pixel_format); - DBG("destroy: FB ID: %d (%p)", fb->base.id, fb); + DBG("destroy: FB ID: %d (%pK)", fb->base.id, fb); drm_framebuffer_cleanup(fb); @@ -178,7 +178,7 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, unsigned int hsub, vsub; bool is_modified = false; - DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", + DBG("create framebuffer: dev=%pK, mode_cmd=%pK (%dx%d@%4.4s)", dev, mode_cmd, mode_cmd->width, mode_cmd->height, (char *)&mode_cmd->pixel_format); @@ -261,7 +261,7 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, goto fail; } - DBG("create: FB ID: %d (%p)", fb->base.id, fb); + DBG("create: FB ID: %d (%pK)", fb->base.id, fb); return fb; diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index e49df634e3f2..14cdd10f29f9 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -146,7 +146,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, goto fail_unlock; } - DBG("fbi=%p, dev=%p", fbi, dev); + DBG("fbi=%pK, dev=%pK", fbi, dev); fbdev->fb = fb; helper->fb = fb; @@ -167,7 +167,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, fbi->fix.smem_start = paddr; fbi->fix.smem_len = fbdev->bo->size; - DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); + DBG("par=%pK, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 05ae5b7e4dc1..69bd4c53df65 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -290,7 +290,7 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) pfn = page_to_pfn(pages[pgoff]); - VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, + VERB("Inserting %pK pfn %lx, pa %lx", vmf->virtual_address, pfn, pfn << PAGE_SHIFT); ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); @@ -399,7 +399,7 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, msm_obj->domain[id].sgt, IOMMU_READ | IOMMU_NOEXEC); if (ret) { - DRM_ERROR("Unable to map phy buf=%p\n", + DRM_ERROR("Unable to map phy buf=%pK\n", (void *)pa); return ret; } @@ -414,7 +414,7 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, msm_obj->domain[id].iova = sg_dma_address(msm_obj->domain[id].sgt->sgl); } - DRM_DEBUG("iova=%p\n", + DRM_DEBUG("iova=%pK\n", (void *)msm_obj->domain[id].iova); } else { WARN_ONCE(1, "physical address being used\n"); @@ -599,7 +599,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) uint64_t off = drm_vma_node_start(&obj->vma_node); WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %zu\n", + seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %pK %zu\n", msm_obj->flags, is_active(msm_obj) ? 'A' : 'I', msm_obj->read_timestamp, msm_obj->write_timestamp, obj->name, obj->refcount.refcount.counter, diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index fd06bf826b2c..b3e5827719ba 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1253,7 +1253,7 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, sde_crtc_install_properties(crtc); - SDE_DEBUG("%s: successfully initialized crtc=%p\n", + SDE_DEBUG("%s: successfully initialized crtc=%pK\n", sde_crtc->name, crtc); return crtc; } diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index 629ca373665c..1a5e0faf9e47 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -133,7 +133,7 @@ struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev, u32 major, struct sde_mdss_cfg *cfg = NULL; if (!dev || !dev->dev) { - SDE_ERROR("dev=%p or dev->dev is NULL\n", dev); + SDE_ERROR("dev=%pK or dev->dev is NULL\n", dev); return NULL; } diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index cffdaad1de32..c013fc135a97 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1506,7 +1506,7 @@ u32 sde_plane_num_of_phy_pipe(struct drm_plane *plane) struct sde_plane *sde_plane = to_sde_plane(plane); if (!plane || !sde_plane) { - SDE_ERROR("plane=%p or sde_plane=%p is NULL\n", + SDE_ERROR("plane=%pK or sde_plane=%pK is NULL\n", plane, sde_plane); return 0; } From 4b2c1dc57cefa53ee767bc7ba03602be9325f1c4 Mon Sep 17 00:00:00 2001 From: andersonchen Date: Fri, 27 Jul 2018 12:04:28 +0800 Subject: [PATCH 080/392] Sync code to OxygenOS 5.0.4 OTA Change-Id: I7c83e245354516a2c4f79cda522cc4931628bb5f Signed-off-by: joshuous --- drivers/usb/core/config.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 20000128b06c..1791e6d68f12 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -643,18 +643,21 @@ void usb_destroy_configuration(struct usb_device *dev) return; if (dev->rawdescriptors) { - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) + for (i = 0; i < dev->descriptor.bNumConfigurations && + i < USB_MAXCONFIG; i++) kfree(dev->rawdescriptors[i]); kfree(dev->rawdescriptors); dev->rawdescriptors = NULL; } - for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { + for (c = 0; c < dev->descriptor.bNumConfigurations && + c < USB_MAXCONFIG; c++) { struct usb_host_config *cf = &dev->config[c]; kfree(cf->string); - for (i = 0; i < cf->desc.bNumInterfaces; i++) { + for (i = 0; i < cf->desc.bNumInterfaces && + i < USB_MAXINTERFACES; i++) { if (cf->intf_cache[i]) kref_put(&cf->intf_cache[i]->ref, usb_release_interface_cache); From 78ddc5d40ffafc739355e107aa1944b2b15ce99d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 13 Dec 2017 11:59:39 +0100 Subject: [PATCH 081/392] UPSTREAM: Revert "USB: core: only clean up what we allocated" This reverts commit 32fd87b3bbf5f7a045546401dfe2894dbbf4d8c3. Alan wrote a better fix for this... Cc: Andrey Konovalov Cc: stable Signed-off-by: Greg Kroah-Hartman (cherry picked from commit cf4df407e0d7cde60a45369c2a3414d18e2d4fdd) [nc: Qualcomm decided to add the commit this one reverts even though the proper fix is readily available... We have it as dd3ad5f60d520] Signed-off-by: Nathan Chancellor --- drivers/usb/core/config.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 1791e6d68f12..20000128b06c 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -643,21 +643,18 @@ void usb_destroy_configuration(struct usb_device *dev) return; if (dev->rawdescriptors) { - for (i = 0; i < dev->descriptor.bNumConfigurations && - i < USB_MAXCONFIG; i++) + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) kfree(dev->rawdescriptors[i]); kfree(dev->rawdescriptors); dev->rawdescriptors = NULL; } - for (c = 0; c < dev->descriptor.bNumConfigurations && - c < USB_MAXCONFIG; c++) { + for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { struct usb_host_config *cf = &dev->config[c]; kfree(cf->string); - for (i = 0; i < cf->desc.bNumInterfaces && - i < USB_MAXINTERFACES; i++) { + for (i = 0; i < cf->desc.bNumInterfaces; i++) { if (cf->intf_cache[i]) kref_put(&cf->intf_cache[i]->ref, usb_release_interface_cache); From 49347a32f2a3d12b80a22a557d8ba575bf106287 Mon Sep 17 00:00:00 2001 From: Dewet Thibaut Date: Mon, 16 Jul 2018 10:49:27 +0200 Subject: [PATCH 082/392] x86/MCE: Remove min interval polling limitation commit fbdb328c6bae0a7c78d75734a738b66b86dffc96 upstream. commit b3b7c4795c ("x86/MCE: Serialize sysfs changes") introduced a min interval limitation when setting the check interval for polled MCEs. However, the logic is that 0 disables polling for corrected MCEs, see Documentation/x86/x86_64/machinecheck. The limitation prevents disabling. Remove this limitation and allow the value 0 to disable polling again. Fixes: b3b7c4795c ("x86/MCE: Serialize sysfs changes") Signed-off-by: Dewet Thibaut Signed-off-by: Alexander Sverdlin [ Massage commit message. ] Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Cc: Tony Luck Cc: linux-edac Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20180716084927.24869-1-alexander.sverdlin@nokia.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index d5d3af159bec..291cb502d141 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -2240,9 +2240,6 @@ static ssize_t store_int_with_restart(struct device *s, if (check_interval == old_check_interval) return ret; - if (check_interval < 1) - check_interval = 1; - mutex_lock(&mce_sysfs_mutex); mce_restart(); mutex_unlock(&mce_sysfs_mutex); From b7bd86d8c5b8cdd2d9f779a844828fdbc7bae94f Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Fri, 20 Jul 2018 17:53:42 -0700 Subject: [PATCH 083/392] fat: fix memory allocation failure handling of match_strdup() commit 35033ab988c396ad7bce3b6d24060c16a9066db8 upstream. In parse_options(), if match_strdup() failed, parse_options() leaves opts->iocharset in unexpected state (i.e. still pointing the freed string). And this can be the cause of double free. To fix, this initialize opts->iocharset always when freeing. Link: http://lkml.kernel.org/r/8736wp9dzc.fsf@mail.parknet.co.jp Signed-off-by: OGAWA Hirofumi Reported-by: syzbot+90b8e10515ae88228a92@syzkaller.appspotmail.com Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/fat/inode.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 75b5a159d607..3df305d6783c 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -610,13 +610,21 @@ static void fat_set_state(struct super_block *sb, brelse(bh); } +static void fat_reset_iocharset(struct fat_mount_options *opts) +{ + if (opts->iocharset != fat_default_iocharset) { + /* Note: opts->iocharset can be NULL here */ + kfree(opts->iocharset); + opts->iocharset = fat_default_iocharset; + } +} + static void delayed_free(struct rcu_head *p) { struct msdos_sb_info *sbi = container_of(p, struct msdos_sb_info, rcu); unload_nls(sbi->nls_disk); unload_nls(sbi->nls_io); - if (sbi->options.iocharset != fat_default_iocharset) - kfree(sbi->options.iocharset); + fat_reset_iocharset(&sbi->options); kfree(sbi); } @@ -1031,7 +1039,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, opts->fs_fmask = opts->fs_dmask = current_umask(); opts->allow_utime = -1; opts->codepage = fat_default_codepage; - opts->iocharset = fat_default_iocharset; + fat_reset_iocharset(opts); if (is_vfat) { opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95; opts->rodir = 0; @@ -1181,8 +1189,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, /* vfat specific */ case Opt_charset: - if (opts->iocharset != fat_default_iocharset) - kfree(opts->iocharset); + fat_reset_iocharset(opts); iocharset = match_strdup(&args[0]); if (!iocharset) return -ENOMEM; @@ -1774,8 +1781,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, iput(fat_inode); unload_nls(sbi->nls_io); unload_nls(sbi->nls_disk); - if (sbi->options.iocharset != fat_default_iocharset) - kfree(sbi->options.iocharset); + fat_reset_iocharset(&sbi->options); sb->s_fs_info = NULL; kfree(sbi); return error; From bfa30d8adceec8633bea60333707fe1208f2f0e9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 Jul 2018 17:26:43 +0200 Subject: [PATCH 084/392] ALSA: rawmidi: Change resized buffers atomically commit 39675f7a7c7e7702f7d5341f1e0d01db746543a0 upstream. The SNDRV_RAWMIDI_IOCTL_PARAMS ioctl may resize the buffers and the current code is racy. For example, the sequencer client may write to buffer while it being resized. As a simple workaround, let's switch to the resized buffer inside the stream runtime lock. Reported-by: syzbot+52f83f0ea8df16932f7f@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/rawmidi.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index f7be2556eb93..57e4ab148fe3 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -645,7 +645,7 @@ static int snd_rawmidi_info_select_user(struct snd_card *card, int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params * params) { - char *newbuf; + char *newbuf, *oldbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; if (substream->append && substream->use_count > 1) @@ -658,13 +658,17 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, - GFP_KERNEL); + newbuf = kmalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; + spin_lock_irq(&runtime->lock); + oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; runtime->avail = runtime->buffer_size; + runtime->appl_ptr = runtime->hw_ptr = 0; + spin_unlock_irq(&runtime->lock); + kfree(oldbuf); } runtime->avail_min = params->avail_min; substream->active_sensing = !params->no_active_sensing; @@ -675,7 +679,7 @@ EXPORT_SYMBOL(snd_rawmidi_output_params); int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params * params) { - char *newbuf; + char *newbuf, *oldbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; snd_rawmidi_drain_input(substream); @@ -686,12 +690,16 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, - GFP_KERNEL); + newbuf = kmalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; + spin_lock_irq(&runtime->lock); + oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; + runtime->appl_ptr = runtime->hw_ptr = 0; + spin_unlock_irq(&runtime->lock); + kfree(oldbuf); } runtime->avail_min = params->avail_min; return 0; From ade78e53ce11db4391b6d3aa0ab9b144e974844b Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Thu, 28 Jun 2018 16:59:14 -0700 Subject: [PATCH 085/392] ARC: Fix CONFIG_SWAP commit 6e3761145a9ba3ce267c330b6bff51cf6a057b06 upstream. swap was broken on ARC due to silly copy-paste issue. We encode offset from swapcache page in __swp_entry() as (off << 13) but were not decoding back in __swp_offset() as (off >> 13) - it was still (off << 13). This finally fixes swap usage on ARC. | # mkswap /dev/sda2 | | # swapon -a -e /dev/sda2 | Adding 500728k swap on /dev/sda2. Priority:-2 extents:1 across:500728k | | # free | total used free shared buffers cached | Mem: 765104 13456 751648 4736 8 4736 | -/+ buffers/cache: 8712 756392 | Swap: 500728 0 500728 Cc: stable@vger.kernel.org Signed-off-by: Alexey Brodkin Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman --- arch/arc/include/asm/pgtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index 7670f33b9ce2..0f12756d6389 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -372,7 +372,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, /* Decode a PTE containing swap "identifier "into constituents */ #define __swp_type(pte_lookalike) (((pte_lookalike).val) & 0x1f) -#define __swp_offset(pte_lookalike) ((pte_lookalike).val << 13) +#define __swp_offset(pte_lookalike) ((pte_lookalike).val >> 13) /* NOPs, to keep generic kernel happy */ #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) From dd385143709f604be9566c9618f800624ae68254 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 11 Jul 2018 10:42:20 -0700 Subject: [PATCH 086/392] ARC: mm: allow mprotect to make stack mappings executable commit 93312b6da4df31e4102ce5420e6217135a16c7ea upstream. mprotect(EXEC) was failing for stack mappings as default vm flags was missing MAYEXEC. This was triggered by glibc test suite nptl/tst-execstack testcase What is surprising is that despite running LTP for years on, we didn't catch this issue as it lacks a directed test case. gcc dejagnu tests with nested functions also requiring exec stack work fine though because they rely on the GNU_STACK segment spit out by compiler and handled in kernel elf loader. This glibc case is different as the stack is non exec to begin with and a dlopen of shared lib with GNU_STACK segment triggers the exec stack proceedings using a mprotect(PROT_EXEC) which was broken. CC: stable@vger.kernel.org Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman --- arch/arc/include/asm/page.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 9c8aa41e45c2..25f6583a7a2c 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -97,7 +97,7 @@ typedef unsigned long pgtable_t; #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) /* Default Permissions for stack/heaps pages (Non Executable) */ -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE) +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #define WANT_PAGE_VIRTUAL 1 From 58635c84de109bf77d04b174d7641e376b0d2c20 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 5 Jul 2018 18:49:23 +0000 Subject: [PATCH 087/392] ipv4: Return EINVAL when ping_group_range sysctl doesn't map to user ns [ Upstream commit 70ba5b6db96ff7324b8cfc87e0d0383cf59c9677 ] The low and high values of the net.ipv4.ping_group_range sysctl were being silently forced to the default disabled state when a write to the sysctl contained GIDs that didn't map to the associated user namespace. Confusingly, the sysctl's write operation would return success and then a subsequent read of the sysctl would indicate that the low and high values are the overflowgid. This patch changes the behavior by clearly returning an error when the sysctl write operation receives a GID range that doesn't map to the associated user namespace. In such a situation, the previous value of the sysctl is preserved and that range will be returned in a subsequent read of the sysctl. Signed-off-by: Tyler Hicks Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/sysctl_net_ipv4.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index d383bd6be279..d6ef0dd85eb4 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -134,8 +134,9 @@ static int ipv4_ping_group_range(struct ctl_table *table, int write, if (write && ret == 0) { low = make_kgid(user_ns, urange[0]); high = make_kgid(user_ns, urange[1]); - if (!gid_valid(low) || !gid_valid(high) || - (urange[1] < urange[0]) || gid_lt(high, low)) { + if (!gid_valid(low) || !gid_valid(high)) + return -EINVAL; + if (urange[1] < urange[0] || gid_lt(high, low)) { low = make_kgid(&init_user_ns, 1); high = make_kgid(&init_user_ns, 0); } From f970e49289206327007ce227034d307182e91219 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 17 Jul 2018 20:17:33 -0500 Subject: [PATCH 088/392] ptp: fix missing break in switch [ Upstream commit 9ba8376ce1e2cbf4ce44f7e4bee1d0648e10d594 ] It seems that a *break* is missing in order to avoid falling through to the default case. Otherwise, checking *chan* makes no sense. Fixes: 72df7a7244c0 ("ptp: Allow reassigning calibration pin function") Signed-off-by: Gustavo A. R. Silva Acked-by: Richard Cochran Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/ptp/ptp_chardev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index f8a76090cbca..52d023514560 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -88,6 +88,7 @@ int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin, case PTP_PF_PHYSYNC: if (chan != 0) return -EINVAL; + break; default: return -EINVAL; } From 8428d1ead1ab0835b12868cb63d8b6d8b37eaa6d Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Wed, 11 Jul 2018 14:39:42 +0200 Subject: [PATCH 089/392] net: Don't copy pfmemalloc flag in __copy_skb_header() [ Upstream commit 8b7008620b8452728cadead460a36f64ed78c460 ] The pfmemalloc flag indicates that the skb was allocated from the PFMEMALLOC reserves, and the flag is currently copied on skb copy and clone. However, an skb copied from an skb flagged with pfmemalloc wasn't necessarily allocated from PFMEMALLOC reserves, and on the other hand an skb allocated that way might be copied from an skb that wasn't. So we should not copy the flag on skb copy, and rather decide whether to allow an skb to be associated with sockets unrelated to page reclaim depending only on how it was allocated. Move the pfmemalloc flag before headers_start[0] using an existing 1-bit hole, so that __copy_skb_header() doesn't copy it. When cloning, we'll now take care of this flag explicitly, contravening to the warning comment of __skb_clone(). While at it, restore the newline usage introduced by commit b19372273164 ("net: reorganize sk_buff for faster __copy_skb_header()") to visually separate bytes used in bitfields after headers_start[0], that was gone after commit a9e419dc7be6 ("netfilter: merge ctinfo into nfct pointer storage area"), and describe the pfmemalloc flag in the kernel-doc structure comment. This doesn't change the size of sk_buff or cacheline boundaries, but consolidates the 15 bits hole before tc_index into a 2 bytes hole before csum, that could now be filled more easily. Reported-by: Patrick Talbert Fixes: c93bdd0e03e8 ("netvm: allow skb allocation to use PFMEMALLOC reserves") Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/skbuff.h | 12 ++++++------ net/core/skbuff.c | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 008a270faf26..d3a85e0c1b00 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -475,6 +475,7 @@ static inline u32 skb_mstamp_us_delta(const struct skb_mstamp *t1, * @hash: the packet hash * @queue_mapping: Queue mapping for multiqueue devices * @xmit_more: More SKBs are pending for this queue + * @pfmemalloc: skbuff was allocated from PFMEMALLOC reserves * @ndisc_nodetype: router type (from link layer) * @ooo_okay: allow the mapping of a socket to a queue to be changed * @l4_hash: indicate hash is a canonical 4-tuple hash over transport @@ -551,8 +552,8 @@ struct sk_buff { fclone:2, peeked:1, head_frag:1, - xmit_more:1; - /* one bit hole */ + xmit_more:1, + pfmemalloc:1; kmemcheck_bitfield_end(flags1); /* fields enclosed in headers_start/headers_end are copied @@ -572,19 +573,18 @@ struct sk_buff { __u8 __pkt_type_offset[0]; __u8 pkt_type:3; - __u8 pfmemalloc:1; __u8 ignore_df:1; __u8 nfctinfo:3; - __u8 nf_trace:1; + __u8 ip_summed:2; __u8 ooo_okay:1; __u8 l4_hash:1; __u8 sw_hash:1; __u8 wifi_acked_valid:1; __u8 wifi_acked:1; - __u8 no_fcs:1; + /* Indicates the inner headers are valid in the skbuff. */ __u8 encapsulation:1; __u8 encap_hdr_csum:1; @@ -592,11 +592,11 @@ struct sk_buff { __u8 csum_complete_sw:1; __u8 csum_level:2; __u8 csum_bad:1; - #ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; #endif __u8 ipvs_property:1; + __u8 inner_protocol_type:1; /* 4 or 6 bit hole */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index ab5b8d0bdccc..86bf7279388d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -780,6 +780,8 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) n->cloned = 1; n->nohdr = 0; n->peeked = 0; + if (skb->pfmemalloc) + n->pfmemalloc = 1; n->destructor = NULL; C(tail); C(end); From 15245b3e79dccb75906920717973ab948a386270 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Fri, 13 Jul 2018 13:21:07 +0200 Subject: [PATCH 090/392] skbuff: Unconditionally copy pfmemalloc in __skb_clone() [ Upstream commit e78bfb0751d4e312699106ba7efbed2bab1a53ca ] Commit 8b7008620b84 ("net: Don't copy pfmemalloc flag in __copy_skb_header()") introduced a different handling for the pfmemalloc flag in copy and clone paths. In __skb_clone(), now, the flag is set only if it was set in the original skb, but not cleared if it wasn't. This is wrong and might lead to socket buffers being flagged with pfmemalloc even if the skb data wasn't allocated from pfmemalloc reserves. Copy the flag instead of ORing it. Reported-by: Sabrina Dubroca Fixes: 8b7008620b84 ("net: Don't copy pfmemalloc flag in __copy_skb_header()") Signed-off-by: Stefano Brivio Tested-by: Sabrina Dubroca Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/skbuff.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 86bf7279388d..fe4c467a4a15 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -780,8 +780,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) n->cloned = 1; n->nohdr = 0; n->peeked = 0; - if (skb->pfmemalloc) - n->pfmemalloc = 1; + C(pfmemalloc); n->destructor = NULL; C(tail); C(end); From 88021f225b9ee2ee63d98fb5bd75a6434737b9b3 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Mon, 23 Jul 2018 16:50:48 +0200 Subject: [PATCH 091/392] ip: hash fragments consistently [ Upstream commit 3dd1c9a1270736029ffca670e9bd0265f4120600 ] The skb hash for locally generated ip[v6] fragments belonging to the same datagram can vary in several circumstances: * for connected UDP[v6] sockets, the first fragment get its hash via set_owner_w()/skb_set_hash_from_sk() * for unconnected IPv6 UDPv6 sockets, the first fragment can get its hash via ip6_make_flowlabel()/skb_get_hash_flowi6(), if auto_flowlabel is enabled For the following frags the hash is usually computed via skb_get_hash(). The above can cause OoO for unconnected IPv6 UDPv6 socket: in that scenario the egress tx queue can be selected on a per packet basis via the skb hash. It may also fool flow-oriented schedulers to place fragments belonging to the same datagram in different flows. Fix the issue by copying the skb hash from the head frag into the others at fragmentation time. Before this commit: perf probe -a "dev_queue_xmit skb skb->hash skb->l4_hash:b1@0/8 skb->sw_hash:b1@1/8" netperf -H $IPV4 -t UDP_STREAM -l 5 -- -m 2000 -n & perf record -e probe:dev_queue_xmit -e probe:skb_set_owner_w -a sleep 0.1 perf script probe:dev_queue_xmit: (ffffffff8c6b1b20) hash=3713014309 l4_hash=1 sw_hash=0 probe:dev_queue_xmit: (ffffffff8c6b1b20) hash=0 l4_hash=0 sw_hash=0 After this commit: probe:dev_queue_xmit: (ffffffff8c6b1b20) hash=2171763177 l4_hash=1 sw_hash=0 probe:dev_queue_xmit: (ffffffff8c6b1b20) hash=2171763177 l4_hash=1 sw_hash=0 Fixes: b73c3d0e4f0e ("net: Save TX flow hash in sock and set in skbuf on xmit") Fixes: 67800f9b1f4e ("ipv6: Call skb_get_hash_flowi6 to get skb->hash in ip6_make_flowlabel") Signed-off-by: Paolo Abeni Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_output.c | 2 ++ net/ipv6/ip6_output.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 88392ebcbc64..f6c8f825ae6b 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -459,6 +459,8 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->dev = from->dev; to->mark = from->mark; + skb_copy_hash(to, from); + /* Copy the flags to each fragment. */ IPCB(to)->flags = IPCB(from)->flags; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 436bd77859e5..087fe616bfaf 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -533,6 +533,8 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->dev = from->dev; to->mark = from->mark; + skb_copy_hash(to, from); + #ifdef CONFIG_NET_SCHED to->tc_index = from->tc_index; #endif From f3f461a94794e75c4c03dd6ce5e3a803163abb45 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 24 Jul 2018 14:27:55 +0300 Subject: [PATCH 092/392] net/mlx4_core: Save the qpn from the input modifier in RST2INIT wrapper [ Upstream commit 958c696f5a7274d9447a458ad7aa70719b29a50a ] Function mlx4_RST2INIT_QP_wrapper saved the qp number passed in the qp context, rather than the one passed in the input modifier. However, the qp number in the qp context is not defined as a required parameter by the FW. Therefore, drivers may choose to not specify the qp number in the qp context for the reset-to-init transition. Thus, we must save the qp number passed in the command input modifier -- which is always present. (This saved qp number is used as the input modifier for command 2RST_QP when a slave's qp's are destroyed). Fixes: c82e9aa0a8bc ("mlx4_core: resource tracking for HCA resources used by guests") Signed-off-by: Jack Morgenstein Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index fbb0c02276f9..816b614025b4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -2709,7 +2709,7 @@ int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, u32 srqn = qp_get_srqn(qpc) & 0xffffff; int use_srq = (qp_get_srqn(qpc) >> 24) & 1; struct res_srq *srq; - int local_qpn = be32_to_cpu(qpc->local_qpn) & 0xffffff; + int local_qpn = vhcr->in_modifier & 0xffffff; err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0); if (err) From 411d7e3c161e8f2036d20896145d4f1c6b0e3f9b Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Fri, 20 Jul 2018 13:21:01 -0700 Subject: [PATCH 093/392] rtnetlink: add rtnl_link_state check in rtnl_configure_link [ Upstream commit 5025f7f7d506fba9b39e7fe8ca10f6f34cb9bc2d ] rtnl_configure_link sets dev->rtnl_link_state to RTNL_LINK_INITIALIZED and unconditionally calls __dev_notify_flags to notify user-space of dev flags. current call sequence for rtnl_configure_link rtnetlink_newlink rtnl_link_ops->newlink rtnl_configure_link (unconditionally notifies userspace of default and new dev flags) If a newlink handler wants to call rtnl_configure_link early, we will end up with duplicate notifications to user-space. This patch fixes rtnl_configure_link to check rtnl_link_state and call __dev_notify_flags with gchanges = 0 if already RTNL_LINK_INITIALIZED. Later in the series, this patch will help the following sequence where a driver implementing newlink can call rtnl_configure_link to initialize the link early. makes the following call sequence work: rtnetlink_newlink rtnl_link_ops->newlink (vxlan) -> rtnl_configure_link (initializes link and notifies user-space of default dev flags) rtnl_configure_link (updates dev flags if requested by user ifm and notifies user-space of new dev flags) Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/rtnetlink.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 9fd2c9eb54e8..51301ad3c2d9 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1842,9 +1842,12 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) return err; } - dev->rtnl_link_state = RTNL_LINK_INITIALIZED; - - __dev_notify_flags(dev, old_flags, ~0U); + if (dev->rtnl_link_state == RTNL_LINK_INITIALIZED) { + __dev_notify_flags(dev, old_flags, 0U); + } else { + dev->rtnl_link_state = RTNL_LINK_INITIALIZED; + __dev_notify_flags(dev, old_flags, ~0U); + } return 0; } EXPORT_SYMBOL(rtnl_configure_link); From 7d776e16ee1da25ceecfadff6264c1b25971f3dd Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Thu, 12 Jul 2018 06:04:52 -0700 Subject: [PATCH 094/392] tcp: fix dctcp delayed ACK schedule [ Upstream commit b0c05d0e99d98d7f0cd41efc1eeec94efdc3325d ] Previously, when a data segment was sent an ACK was piggybacked on the data segment without generating a CA_EVENT_NON_DELAYED_ACK event to notify congestion control modules. So the DCTCP ca->delayed_ack_reserved flag could incorrectly stay set when in fact there were no delayed ACKs being reserved. This could result in sending a special ECN notification ACK that carries an older ACK sequence, when in fact there was no need for such an ACK. DCTCP keeps track of the delayed ACK status with its own separate state ca->delayed_ack_reserved. Previously it may accidentally cancel the delayed ACK without updating this field upon sending a special ACK that carries a older ACK sequence. This inconsistency would lead to DCTCP receiver never acknowledging the latest data until the sender times out and retry in some cases. Packetdrill script (provided by Larry Brakmo) 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 0.000 setsockopt(3, SOL_TCP, TCP_CONGESTION, "dctcp", 5) = 0 0.000 bind(3, ..., ...) = 0 0.000 listen(3, 1) = 0 0.100 < [ect0] SEW 0:0(0) win 32792 0.100 > SE. 0:0(0) ack 1 0.110 < [ect0] . 1:1(0) ack 1 win 257 0.200 accept(3, ..., ...) = 4 0.200 < [ect0] . 1:1001(1000) ack 1 win 257 0.200 > [ect01] . 1:1(0) ack 1001 0.200 write(4, ..., 1) = 1 0.200 > [ect01] P. 1:2(1) ack 1001 0.200 < [ect0] . 1001:2001(1000) ack 2 win 257 0.200 write(4, ..., 1) = 1 0.200 > [ect01] P. 2:3(1) ack 2001 0.200 < [ect0] . 2001:3001(1000) ack 3 win 257 0.200 < [ect0] . 3001:4001(1000) ack 3 win 257 0.200 > [ect01] . 3:3(0) ack 4001 0.210 < [ce] P. 4001:4501(500) ack 3 win 257 +0.001 read(4, ..., 4500) = 4500 +0 write(4, ..., 1) = 1 +0 > [ect01] PE. 3:4(1) ack 4501 +0.010 < [ect0] W. 4501:5501(1000) ack 4 win 257 // Previously the ACK sequence below would be 4501, causing a long RTO +0.040~+0.045 > [ect01] . 4:4(0) ack 5501 // delayed ack +0.311 < [ect0] . 5501:6501(1000) ack 4 win 257 // More data +0 > [ect01] . 4:4(0) ack 6501 // now acks everything +0.500 < F. 9501:9501(0) ack 4 win 257 Reported-by: Larry Brakmo Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Acked-by: Neal Cardwell Acked-by: Lawrence Brakmo Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_dctcp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index b504371af742..33e74cb51b89 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -131,7 +131,8 @@ static void dctcp_ce_state_0_to_1(struct sock *sk) /* State has changed from CE=0 to CE=1 and delayed * ACK has not sent yet. */ - if (!ca->ce_state && ca->delayed_ack_reserved) { + if (!ca->ce_state && + inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) { u32 tmp_rcv_nxt; /* Save current rcv_nxt. */ @@ -161,7 +162,8 @@ static void dctcp_ce_state_1_to_0(struct sock *sk) /* State has changed from CE=1 to CE=0 and delayed * ACK has not sent yet. */ - if (ca->ce_state && ca->delayed_ack_reserved) { + if (ca->ce_state && + inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) { u32 tmp_rcv_nxt; /* Save current rcv_nxt. */ From e76a28ca1f536df0c7f6c5631e76a1eeda8f8cef Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 18 Jul 2018 13:56:34 -0700 Subject: [PATCH 095/392] tcp: helpers to send special DCTCP ack [ Upstream commit 2987babb6982306509380fc11b450227a844493b ] Refactor and create helpers to send the special ACK in DCTCP. Signed-off-by: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_output.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index add262e8d8df..371ea9e76bd1 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -884,8 +884,8 @@ void tcp_wfree(struct sk_buff *skb) * We are working here with either a clone of the original * SKB, or a fresh unique copy made by the retransmit engine. */ -static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, - gfp_t gfp_mask) +static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + int clone_it, gfp_t gfp_mask, u32 rcv_nxt) { const struct inet_connection_sock *icsk = inet_csk(sk); struct inet_sock *inet; @@ -948,7 +948,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, th->source = inet->inet_sport; th->dest = inet->inet_dport; th->seq = htonl(tcb->seq); - th->ack_seq = htonl(tp->rcv_nxt); + th->ack_seq = htonl(rcv_nxt); *(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) | tcb->tcp_flags); @@ -1019,6 +1019,13 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, return net_xmit_eval(err); } +static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, + gfp_t gfp_mask) +{ + return __tcp_transmit_skb(sk, skb, clone_it, gfp_mask, + tcp_sk(sk)->rcv_nxt); +} + /* This routine just queues the buffer for sending. * * NOTE: probe0 timer is not checked, do not forget tcp_push_pending_frames, @@ -3220,7 +3227,7 @@ void tcp_send_delayed_ack(struct sock *sk) } /* This routine sends an ack and also updates the window. */ -void tcp_send_ack(struct sock *sk) +void __tcp_send_ack(struct sock *sk, u32 rcv_nxt) { struct sk_buff *buff; @@ -3249,7 +3256,12 @@ void tcp_send_ack(struct sock *sk) /* Send it off, this clears delayed acks for us. */ skb_mstamp_get(&buff->skb_mstamp); - tcp_transmit_skb(sk, buff, 0, sk_gfp_atomic(sk, GFP_ATOMIC)); + __tcp_transmit_skb(sk, buff, 0, sk_gfp_atomic(sk, GFP_ATOMIC), rcv_nxt); +} + +void tcp_send_ack(struct sock *sk) +{ + __tcp_send_ack(sk, tcp_sk(sk)->rcv_nxt); } EXPORT_SYMBOL_GPL(tcp_send_ack); From 8c11f488b6f415a9c7d91cc09fec939b256c05be Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 18 Jul 2018 13:56:35 -0700 Subject: [PATCH 096/392] tcp: do not cancel delay-AcK on DCTCP special ACK [ Upstream commit 27cde44a259c380a3c09066fc4b42de7dde9b1ad ] Currently when a DCTCP receiver delays an ACK and receive a data packet with a different CE mark from the previous one's, it sends two immediate ACKs acking previous and latest sequences respectly (for ECN accounting). Previously sending the first ACK may mark off the delayed ACK timer (tcp_event_ack_sent). This may subsequently prevent sending the second ACK to acknowledge the latest sequence (tcp_ack_snd_check). The culprit is that tcp_send_ack() assumes it always acknowleges the latest sequence, which is not true for the first special ACK. The fix is to not make the assumption in tcp_send_ack and check the actual ack sequence before cancelling the delayed ACK. Further it's safer to pass the ack sequence number as a local variable into tcp_send_ack routine, instead of intercepting tp->rcv_nxt to avoid future bugs like this. Reported-by: Neal Cardwell Signed-off-by: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/tcp.h | 1 + net/ipv4/tcp_dctcp.c | 34 ++++------------------------------ net/ipv4/tcp_output.c | 11 ++++++++--- 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 15564a2cc28c..521490fd8928 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -530,6 +530,7 @@ int tcp_send_synack(struct sock *); bool tcp_syn_flood_action(struct sock *sk, const struct sk_buff *skb, const char *proto); void tcp_push_one(struct sock *, unsigned int mss_now); +void __tcp_send_ack(struct sock *sk, u32 rcv_nxt); void tcp_send_ack(struct sock *sk); void tcp_send_delayed_ack(struct sock *sk); void tcp_send_loss_probe(struct sock *sk); diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index 33e74cb51b89..faab1c0e4c26 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -132,21 +132,8 @@ static void dctcp_ce_state_0_to_1(struct sock *sk) * ACK has not sent yet. */ if (!ca->ce_state && - inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) { - u32 tmp_rcv_nxt; - - /* Save current rcv_nxt. */ - tmp_rcv_nxt = tp->rcv_nxt; - - /* Generate previous ack with CE=0. */ - tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; - tp->rcv_nxt = ca->prior_rcv_nxt; - - tcp_send_ack(sk); - - /* Recover current rcv_nxt. */ - tp->rcv_nxt = tmp_rcv_nxt; - } + inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) + __tcp_send_ack(sk, ca->prior_rcv_nxt); ca->prior_rcv_nxt = tp->rcv_nxt; ca->ce_state = 1; @@ -163,21 +150,8 @@ static void dctcp_ce_state_1_to_0(struct sock *sk) * ACK has not sent yet. */ if (ca->ce_state && - inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) { - u32 tmp_rcv_nxt; - - /* Save current rcv_nxt. */ - tmp_rcv_nxt = tp->rcv_nxt; - - /* Generate previous ack with CE=1. */ - tp->ecn_flags |= TCP_ECN_DEMAND_CWR; - tp->rcv_nxt = ca->prior_rcv_nxt; - - tcp_send_ack(sk); - - /* Recover current rcv_nxt. */ - tp->rcv_nxt = tmp_rcv_nxt; - } + inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) + __tcp_send_ack(sk, ca->prior_rcv_nxt); ca->prior_rcv_nxt = tp->rcv_nxt; ca->ce_state = 0; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 371ea9e76bd1..a3c701e079fd 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -183,8 +183,13 @@ static void tcp_event_data_sent(struct tcp_sock *tp, } /* Account for an ACK we sent. */ -static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts) +static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts, + u32 rcv_nxt) { + struct tcp_sock *tp = tcp_sk(sk); + + if (unlikely(rcv_nxt != tp->rcv_nxt)) + return; /* Special ACK sent by DCTCP to reflect ECN */ tcp_dec_quickack_mode(sk, pkts); inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK); } @@ -990,7 +995,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, icsk->icsk_af_ops->send_check(sk, skb); if (likely(tcb->tcp_flags & TCPHDR_ACK)) - tcp_event_ack_sent(sk, tcp_skb_pcount(skb)); + tcp_event_ack_sent(sk, tcp_skb_pcount(skb), rcv_nxt); if (skb->len != tcp_header_size) tcp_event_data_sent(tp, sk); @@ -3258,12 +3263,12 @@ void __tcp_send_ack(struct sock *sk, u32 rcv_nxt) skb_mstamp_get(&buff->skb_mstamp); __tcp_transmit_skb(sk, buff, 0, sk_gfp_atomic(sk, GFP_ATOMIC), rcv_nxt); } +EXPORT_SYMBOL_GPL(__tcp_send_ack); void tcp_send_ack(struct sock *sk) { __tcp_send_ack(sk, tcp_sk(sk)->rcv_nxt); } -EXPORT_SYMBOL_GPL(tcp_send_ack); /* This routine sends a packet with an out of date sequence * number. It assumes the other end will try to ack it. From 1e758a79523c55185667c476e2c6a2736007e7da Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 18 Jul 2018 13:56:36 -0700 Subject: [PATCH 097/392] tcp: do not delay ACK in DCTCP upon CE status change [ Upstream commit a0496ef2c23b3b180902dd185d0d63ccbc624cf8 ] Per DCTCP RFC8257 (Section 3.2) the ACK reflecting the CE status change has to be sent immediately so the sender can respond quickly: """ When receiving packets, the CE codepoint MUST be processed as follows: 1. If the CE codepoint is set and DCTCP.CE is false, set DCTCP.CE to true and send an immediate ACK. 2. If the CE codepoint is not set and DCTCP.CE is true, set DCTCP.CE to false and send an immediate ACK. """ Previously DCTCP implementation may continue to delay the ACK. This patch fixes that to implement the RFC by forcing an immediate ACK. Tested with this packetdrill script provided by Larry Brakmo 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 0.000 setsockopt(3, SOL_TCP, TCP_CONGESTION, "dctcp", 5) = 0 0.000 bind(3, ..., ...) = 0 0.000 listen(3, 1) = 0 0.100 < [ect0] SEW 0:0(0) win 32792 0.100 > SE. 0:0(0) ack 1 0.110 < [ect0] . 1:1(0) ack 1 win 257 0.200 accept(3, ..., ...) = 4 +0 setsockopt(4, SOL_SOCKET, SO_DEBUG, [1], 4) = 0 0.200 < [ect0] . 1:1001(1000) ack 1 win 257 0.200 > [ect01] . 1:1(0) ack 1001 0.200 write(4, ..., 1) = 1 0.200 > [ect01] P. 1:2(1) ack 1001 0.200 < [ect0] . 1001:2001(1000) ack 2 win 257 +0.005 < [ce] . 2001:3001(1000) ack 2 win 257 +0.000 > [ect01] . 2:2(0) ack 2001 // Previously the ACK below would be delayed by 40ms +0.000 > [ect01] E. 2:2(0) ack 3001 +0.500 < F. 9501:9501(0) ack 4 win 257 Signed-off-by: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/tcp.h | 1 + net/ipv4/tcp_dctcp.c | 30 ++++++++++++++++++------------ net/ipv4/tcp_input.c | 3 ++- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 521490fd8928..b362f9abae3b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -372,6 +372,7 @@ ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); +void tcp_enter_quickack_mode(struct sock *sk); static inline void tcp_dec_quickack_mode(struct sock *sk, const unsigned int pkts) { diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index faab1c0e4c26..ddd84ed7fb38 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -128,12 +128,15 @@ static void dctcp_ce_state_0_to_1(struct sock *sk) struct dctcp *ca = inet_csk_ca(sk); struct tcp_sock *tp = tcp_sk(sk); - /* State has changed from CE=0 to CE=1 and delayed - * ACK has not sent yet. - */ - if (!ca->ce_state && - inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) - __tcp_send_ack(sk, ca->prior_rcv_nxt); + if (!ca->ce_state) { + /* State has changed from CE=0 to CE=1, force an immediate + * ACK to reflect the new CE state. If an ACK was delayed, + * send that first to reflect the prior CE state. + */ + if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) + __tcp_send_ack(sk, ca->prior_rcv_nxt); + tcp_enter_quickack_mode(sk); + } ca->prior_rcv_nxt = tp->rcv_nxt; ca->ce_state = 1; @@ -146,12 +149,15 @@ static void dctcp_ce_state_1_to_0(struct sock *sk) struct dctcp *ca = inet_csk_ca(sk); struct tcp_sock *tp = tcp_sk(sk); - /* State has changed from CE=1 to CE=0 and delayed - * ACK has not sent yet. - */ - if (ca->ce_state && - inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) - __tcp_send_ack(sk, ca->prior_rcv_nxt); + if (ca->ce_state) { + /* State has changed from CE=1 to CE=0, force an immediate + * ACK to reflect the new CE state. If an ACK was delayed, + * send that first to reflect the prior CE state. + */ + if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) + __tcp_send_ack(sk, ca->prior_rcv_nxt); + tcp_enter_quickack_mode(sk); + } ca->prior_rcv_nxt = tp->rcv_nxt; ca->ce_state = 0; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e81a5711dd4f..3466d5716d1c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -182,13 +182,14 @@ static void tcp_incr_quickack(struct sock *sk) icsk->icsk_ack.quick = min(quickacks, TCP_MAX_QUICKACKS); } -static void tcp_enter_quickack_mode(struct sock *sk) +void tcp_enter_quickack_mode(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); tcp_incr_quickack(sk); icsk->icsk_ack.pingpong = 0; icsk->icsk_ack.ato = TCP_ATO_MIN; } +EXPORT_SYMBOL(tcp_enter_quickack_mode); /* Send ACKs quickly, if "quick" count is not exhausted * and the session is not interactive. From 25c28af9ee6a9cfeeb9245e174b3b65d70e614b2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:18 -0700 Subject: [PATCH 098/392] tcp: avoid collapses in tcp_prune_queue() if possible [ Upstream commit f4a3313d8e2ca9fd8d8f45e40a2903ba782607e7 ] Right after a TCP flow is created, receiving tiny out of order packets allways hit the condition : if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) tcp_clamp_window(sk); tcp_clamp_window() increases sk_rcvbuf to match sk_rmem_alloc (guarded by tcp_rmem[2]) Calling tcp_collapse_ofo_queue() in this case is not useful, and offers a O(N^2) surface attack to malicious peers. Better not attempt anything before full queue capacity is reached, forcing attacker to spend lots of resource and allow us to more easily detect the abuse. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3466d5716d1c..7dd31aec8b48 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4738,6 +4738,9 @@ static int tcp_prune_queue(struct sock *sk) else if (sk_under_memory_pressure(sk)) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); + if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) + return 0; + tcp_collapse_ofo_queue(sk); if (!skb_queue_empty(&sk->sk_receive_queue)) tcp_collapse(sk, &sk->sk_receive_queue, From d932145a840ebc81e7a029a0531cad8f7a1f0932 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:19 -0700 Subject: [PATCH 099/392] tcp: detect malicious patterns in tcp_collapse_ofo_queue() [ Upstream commit 3d4bf93ac12003f9b8e1e2de37fe27983deebdcf ] In case an attacker feeds tiny packets completely out of order, tcp_collapse_ofo_queue() might scan the whole rb-tree, performing expensive copies, but not changing socket memory usage at all. 1) Do not attempt to collapse tiny skbs. 2) Add logic to exit early when too many tiny skbs are detected. We prefer not doing aggressive collapsing (which copies packets) for pathological flows, and revert to tcp_prune_ofo_queue() which will be less expensive. In the future, we might add the possibility of terminating flows that are proven to be malicious. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7dd31aec8b48..dee70277f12f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4652,6 +4652,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, static void tcp_collapse_ofo_queue(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); + u32 range_truesize, sum_tiny = 0; struct sk_buff *skb = skb_peek(&tp->out_of_order_queue); struct sk_buff *head; u32 start, end; @@ -4661,6 +4662,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk) start = TCP_SKB_CB(skb)->seq; end = TCP_SKB_CB(skb)->end_seq; + range_truesize = skb->truesize; head = skb; for (;;) { @@ -4675,14 +4677,24 @@ static void tcp_collapse_ofo_queue(struct sock *sk) if (!skb || after(TCP_SKB_CB(skb)->seq, end) || before(TCP_SKB_CB(skb)->end_seq, start)) { - tcp_collapse(sk, &tp->out_of_order_queue, - head, skb, start, end); + /* Do not attempt collapsing tiny skbs */ + if (range_truesize != head->truesize || + end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) { + tcp_collapse(sk, &tp->out_of_order_queue, + head, skb, start, end); + } else { + sum_tiny += range_truesize; + if (sum_tiny > sk->sk_rcvbuf >> 3) + return; + } + head = skb; if (!skb) break; /* Start new segment */ start = TCP_SKB_CB(skb)->seq; end = TCP_SKB_CB(skb)->end_seq; + range_truesize = skb->truesize; } else { if (before(TCP_SKB_CB(skb)->seq, start)) start = TCP_SKB_CB(skb)->seq; From fd620d990b52c7633c65809824034a45424af2b1 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 10 Jul 2018 08:28:49 +0200 Subject: [PATCH 100/392] usb: cdc_acm: Add quirk for Castles VEGA3000 commit 1445cbe476fc3dd09c0b380b206526a49403c071 upstream. The device (a POS terminal) implements CDC ACM, but has not union descriptor. Signed-off-by: Lubomir Rintel Acked-by: Oliver Neukum Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e01d39509172..fabf77fca4ad 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1785,6 +1785,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x09d8, 0x0320), /* Elatec GmbH TWN3 */ .driver_info = NO_UNION_NORMAL, /* has misplaced union descriptor */ }, + { USB_DEVICE(0x0ca6, 0xa050), /* Castles VEGA3000 */ + .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ + }, { USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */ .driver_info = CLEAR_HALT_CONDITIONS, From 72254c8771854ac83492cac200618b13ad128cb6 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 19 Jul 2018 14:39:37 -0500 Subject: [PATCH 101/392] usb: core: handle hub C_PORT_OVER_CURRENT condition commit 249a32b7eeb3edb6897dd38f89651a62163ac4ed upstream. Based on USB2.0 Spec Section 11.12.5, "If a hub has per-port power switching and per-port current limiting, an over-current on one port may still cause the power on another port to fall below specific minimums. In this case, the affected port is placed in the Power-Off state and C_PORT_OVER_CURRENT is set for the port, but PORT_OVER_CURRENT is not set." so let's check C_PORT_OVER_CURRENT too for over current condition. Fixes: 08d1dec6f405 ("usb:hub set hub->change_bits when over-current happens") Cc: Tested-by: Alessandro Antenucci Signed-off-by: Bin Liu Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 12486efb043f..3d15b5fc9336 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1151,10 +1151,14 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) if (!udev || udev->state == USB_STATE_NOTATTACHED) { /* Tell hub_wq to disconnect the device or - * check for a new connection + * check for a new connection or over current condition. + * Based on USB2.0 Spec Section 11.12.5, + * C_PORT_OVER_CURRENT could be set while + * PORT_OVER_CURRENT is not. So check for any of them. */ if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || - (portstatus & USB_PORT_STAT_OVERCURRENT)) + (portstatus & USB_PORT_STAT_OVERCURRENT) || + (portchange & USB_PORT_STAT_C_OVERCURRENT)) set_bit(port1, hub->change_bits); } else if (portstatus & USB_PORT_STAT_ENABLE) { From ce03b315ba7a2362b41d5ff99370a87ec34c1cf8 Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Mon, 2 Jul 2018 12:48:08 -0700 Subject: [PATCH 102/392] usb: gadget: f_fs: Only return delayed status when len is 0 commit 4d644abf25698362bd33d17c9ddc8f7122c30f17 upstream. Commit 1b9ba000 ("Allow function drivers to pause control transfers") states that USB_GADGET_DELAYED_STATUS is only supported if data phase is 0 bytes. It seems that when the length is not 0 bytes, there is no need to explicitly delay the data stage since the transfer is not completed until the user responds. However, when the length is 0, there is no data stage and the transfer is finished once setup() returns, hence there is a need to explicitly delay completion. This manifests as the following bugs: Prior to 946ef68ad4e4 ('Let setup() return USB_GADGET_DELAYED_STATUS'), when setup is 0 bytes, ffs would require user to queue a 0 byte request in order to clear setup state. However, that 0 byte request was actually not needed and would hang and cause errors in other setup requests. After the above commit, 0 byte setups work since the gadget now accepts empty queues to ep0 to clear the delay, but all other setups hang. Fixes: 946ef68ad4e4 ("Let setup() return USB_GADGET_DELAYED_STATUS") Signed-off-by: Jerry Zhang Cc: stable Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index fc4cb35561b1..570e6100134f 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2987,7 +2987,7 @@ static int ffs_func_setup(struct usb_function *f, __ffs_event_add(ffs, FUNCTIONFS_SETUP); spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); - return USB_GADGET_DELAYED_STATUS; + return creq->wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0; } static void ffs_func_suspend(struct usb_function *f) From e7337c5f58d70202548c39adf85c6a4c5a001e7a Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Tue, 7 Feb 2017 17:01:14 +0200 Subject: [PATCH 103/392] can: xilinx_can: fix RX loop if RXNEMP is asserted without RXOK commit 32852c561bffd613d4ed7ec464b1e03e1b7b6c5c upstream. If the device gets into a state where RXNEMP (RX FIFO not empty) interrupt is asserted without RXOK (new frame received successfully) interrupt being asserted, xcan_rx_poll() will continue to try to clear RXNEMP without actually reading frames from RX FIFO. If the RX FIFO is not empty, the interrupt will not be cleared and napi_schedule() will just be called again. This situation can occur when: (a) xcan_rx() returns without reading RX FIFO due to an error condition. The code tries to clear both RXOK and RXNEMP but RXNEMP will not clear due to a frame still being in the FIFO. The frame will never be read from the FIFO as RXOK is no longer set. (b) A frame is received between xcan_rx_poll() reading interrupt status and clearing RXOK. RXOK will be cleared, but RXNEMP will again remain set as the new message is still in the FIFO. I'm able to trigger case (b) by flooding the bus with frames under load. There does not seem to be any benefit in using both RXNEMP and RXOK in the way the driver does, and the polling example in the reference manual (UG585 v1.10 18.3.7 Read Messages from RxFIFO) also says that either RXOK or RXNEMP can be used for detecting incoming messages. Fix the issue and simplify the RX processing by only using RXNEMP without RXOK. Tested with the integrated CAN on Zynq-7000 SoC. Fixes: b1201e44f50b ("can: xilinx CAN controller support") Signed-off-by: Anssi Hannula Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/xilinx_can.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 8a998e3884ce..09b954d2a655 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -100,7 +100,7 @@ enum xcan_reg { #define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ - XCAN_IXR_ARBLST_MASK | XCAN_IXR_RXOK_MASK) + XCAN_IXR_ARBLST_MASK) /* CAN register bit shift - XCAN___SHIFT */ #define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ @@ -710,15 +710,7 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota) isr = priv->read_reg(priv, XCAN_ISR_OFFSET); while ((isr & XCAN_IXR_RXNEMP_MASK) && (work_done < quota)) { - if (isr & XCAN_IXR_RXOK_MASK) { - priv->write_reg(priv, XCAN_ICR_OFFSET, - XCAN_IXR_RXOK_MASK); - work_done += xcan_rx(ndev); - } else { - priv->write_reg(priv, XCAN_ICR_OFFSET, - XCAN_IXR_RXNEMP_MASK); - break; - } + work_done += xcan_rx(ndev); priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK); isr = priv->read_reg(priv, XCAN_ISR_OFFSET); } @@ -729,7 +721,7 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota) if (work_done < quota) { napi_complete(napi); ier = priv->read_reg(priv, XCAN_IER_OFFSET); - ier |= (XCAN_IXR_RXOK_MASK | XCAN_IXR_RXNEMP_MASK); + ier |= XCAN_IXR_RXNEMP_MASK; priv->write_reg(priv, XCAN_IER_OFFSET, ier); } return work_done; @@ -801,9 +793,9 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) } /* Check for the type of receive interrupt and Processing it */ - if (isr & (XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK)) { + if (isr & XCAN_IXR_RXNEMP_MASK) { ier = priv->read_reg(priv, XCAN_IER_OFFSET); - ier &= ~(XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK); + ier &= ~XCAN_IXR_RXNEMP_MASK; priv->write_reg(priv, XCAN_IER_OFFSET, ier); napi_schedule(&priv->napi); } From 159b65a11c7485cce2784f99a715486ba870a6f4 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Tue, 7 Feb 2017 13:23:04 +0200 Subject: [PATCH 104/392] can: xilinx_can: fix device dropping off bus on RX overrun commit 2574fe54515ed3487405de329e4e9f13d7098c10 upstream. The xilinx_can driver performs a software reset when an RX overrun is detected. This causes the device to enter Configuration mode where no messages are received or transmitted. The documentation does not mention any need to perform a reset on an RX overrun, and testing by inducing an RX overflow also indicated that the device continues to work just fine without a reset. Remove the software reset. Tested with the integrated CAN on Zynq-7000 SoC. Fixes: b1201e44f50b ("can: xilinx CAN controller support") Signed-off-by: Anssi Hannula Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/xilinx_can.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 09b954d2a655..c88fb37a9b04 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -598,7 +598,6 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) if (isr & XCAN_IXR_RXOFLW_MASK) { stats->rx_over_errors++; stats->rx_errors++; - priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); if (skb) { cf->can_id |= CAN_ERR_CRTL; cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; From 0e368141b2f4acf0cd26bea6aae19a3501af3841 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 23 Feb 2017 14:50:03 +0200 Subject: [PATCH 105/392] can: xilinx_can: keep only 1-2 frames in TX FIFO to fix TX accounting commit 620050d9c2be15c47017ba95efe59e0832e99a56 upstream. The xilinx_can driver assumes that the TXOK interrupt only clears after it has been acknowledged as many times as there have been successfully sent frames. However, the documentation does not mention such behavior, instead saying just that the interrupt is cleared when the clear bit is set. Similarly, testing seems to also suggest that it is immediately cleared regardless of the amount of frames having been sent. Performing some heavy TX load and then going back to idle has the tx_head drifting further away from tx_tail over time, steadily reducing the amount of frames the driver keeps in the TX FIFO (but not to zero, as the TXOK interrupt always frees up space for 1 frame from the driver's perspective, so frames continue to be sent) and delaying the local echo frames. The TX FIFO tracking is also otherwise buggy as it does not account for TX FIFO being cleared after software resets, causing BUG!, TX FIFO full when queue awake! messages to be output. There does not seem to be any way to accurately track the state of the TX FIFO for local echo support while using the full TX FIFO. The Zynq version of the HW (but not the soft-AXI version) has watermark programming support and with it an additional TX-FIFO-empty interrupt bit. Modify the driver to only put 1 frame into TX FIFO at a time on soft-AXI and 2 frames at a time on Zynq. On Zynq the TXFEMP interrupt bit is used to detect whether 1 or 2 frames have been sent at interrupt processing time. Tested with the integrated CAN on Zynq-7000 SoC. The 1-frame-FIFO mode was also tested. An alternative way to solve this would be to drop local echo support but keep using the full TX FIFO. v2: Add FIFO space check before TX queue wake with locking to synchronize with queue stop. This avoids waking the queue when xmit() had just filled it. v3: Keep local echo support and reduce the amount of frames in FIFO instead as suggested by Marc Kleine-Budde. Fixes: b1201e44f50b ("can: xilinx CAN controller support") Signed-off-by: Anssi Hannula Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/xilinx_can.c | 79 ++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index c88fb37a9b04..fd557e7a4410 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -25,8 +25,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -117,6 +119,7 @@ enum xcan_reg { /** * struct xcan_priv - This definition define CAN driver instance * @can: CAN private data structure. + * @tx_lock: Lock for synchronizing TX interrupt handling * @tx_head: Tx CAN packets ready to send on the queue * @tx_tail: Tx CAN packets successfully sended on the queue * @tx_max: Maximum number packets the driver can send @@ -131,6 +134,7 @@ enum xcan_reg { */ struct xcan_priv { struct can_priv can; + spinlock_t tx_lock; unsigned int tx_head; unsigned int tx_tail; unsigned int tx_max; @@ -158,6 +162,11 @@ static const struct can_bittiming_const xcan_bittiming_const = { .brp_inc = 1, }; +#define XCAN_CAP_WATERMARK 0x0001 +struct xcan_devtype_data { + unsigned int caps; +}; + /** * xcan_write_reg_le - Write a value to the device register little endian * @priv: Driver private data structure @@ -237,6 +246,10 @@ static int set_reset_mode(struct net_device *ndev) usleep_range(500, 10000); } + /* reset clears FIFOs */ + priv->tx_head = 0; + priv->tx_tail = 0; + return 0; } @@ -391,6 +404,7 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct net_device_stats *stats = &ndev->stats; struct can_frame *cf = (struct can_frame *)skb->data; u32 id, dlc, data[2] = {0, 0}; + unsigned long flags; if (can_dropped_invalid_skb(ndev, skb)) return NETDEV_TX_OK; @@ -438,6 +452,9 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) data[1] = be32_to_cpup((__be32 *)(cf->data + 4)); can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max); + + spin_lock_irqsave(&priv->tx_lock, flags); + priv->tx_head++; /* Write the Frame to Xilinx CAN TX FIFO */ @@ -453,10 +470,16 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) stats->tx_bytes += cf->can_dlc; } + /* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */ + if (priv->tx_max > 1) + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXFEMP_MASK); + /* Check if the TX buffer is full */ if ((priv->tx_head - priv->tx_tail) == priv->tx_max) netif_stop_queue(ndev); + spin_unlock_irqrestore(&priv->tx_lock, flags); + return NETDEV_TX_OK; } @@ -1023,6 +1046,18 @@ static int __maybe_unused xcan_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(xcan_dev_pm_ops, xcan_suspend, xcan_resume); +static const struct xcan_devtype_data xcan_zynq_data = { + .caps = XCAN_CAP_WATERMARK, +}; + +/* Match table for OF platform binding */ +static const struct of_device_id xcan_of_match[] = { + { .compatible = "xlnx,zynq-can-1.0", .data = &xcan_zynq_data }, + { .compatible = "xlnx,axi-can-1.00.a", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, xcan_of_match); + /** * xcan_probe - Platform registration call * @pdev: Handle to the platform device structure @@ -1037,8 +1072,10 @@ static int xcan_probe(struct platform_device *pdev) struct resource *res; /* IO mem resources */ struct net_device *ndev; struct xcan_priv *priv; + const struct of_device_id *of_id; + int caps = 0; void __iomem *addr; - int ret, rx_max, tx_max; + int ret, rx_max, tx_max, tx_fifo_depth; /* Get the virtual base address for the device */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1048,7 +1085,8 @@ static int xcan_probe(struct platform_device *pdev) goto err; } - ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", &tx_max); + ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", + &tx_fifo_depth); if (ret < 0) goto err; @@ -1056,6 +1094,30 @@ static int xcan_probe(struct platform_device *pdev) if (ret < 0) goto err; + of_id = of_match_device(xcan_of_match, &pdev->dev); + if (of_id) { + const struct xcan_devtype_data *devtype_data = of_id->data; + + if (devtype_data) + caps = devtype_data->caps; + } + + /* There is no way to directly figure out how many frames have been + * sent when the TXOK interrupt is processed. If watermark programming + * is supported, we can have 2 frames in the FIFO and use TXFEMP + * to determine if 1 or 2 frames have been sent. + * Theoretically we should be able to use TXFWMEMP to determine up + * to 3 frames, but it seems that after putting a second frame in the + * FIFO, with watermark at 2 frames, it can happen that TXFWMEMP (less + * than 2 frames in FIFO) is set anyway with no TXOK (a frame was + * sent), which is not a sensible state - possibly TXFWMEMP is not + * completely synchronized with the rest of the bits? + */ + if (caps & XCAN_CAP_WATERMARK) + tx_max = min(tx_fifo_depth, 2); + else + tx_max = 1; + /* Create a CAN device instance */ ndev = alloc_candev(sizeof(struct xcan_priv), tx_max); if (!ndev) @@ -1070,6 +1132,7 @@ static int xcan_probe(struct platform_device *pdev) CAN_CTRLMODE_BERR_REPORTING; priv->reg_base = addr; priv->tx_max = tx_max; + spin_lock_init(&priv->tx_lock); /* Get IRQ for the device */ ndev->irq = platform_get_irq(pdev, 0); @@ -1137,9 +1200,9 @@ static int xcan_probe(struct platform_device *pdev) devm_can_led_init(ndev); clk_disable_unprepare(priv->bus_clk); clk_disable_unprepare(priv->can_clk); - netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n", + netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth: actual %d, using %d\n", priv->reg_base, ndev->irq, priv->can.clock.freq, - priv->tx_max); + tx_fifo_depth, priv->tx_max); return 0; @@ -1175,14 +1238,6 @@ static int xcan_remove(struct platform_device *pdev) return 0; } -/* Match table for OF platform binding */ -static struct of_device_id xcan_of_match[] = { - { .compatible = "xlnx,zynq-can-1.0", }, - { .compatible = "xlnx,axi-can-1.00.a", }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(of, xcan_of_match); - static struct platform_driver xcan_driver = { .probe = xcan_probe, .remove = xcan_remove, From 57a617aa6ad62e6e798eb7de6e1ed9c2e9affc7c Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Mon, 26 Feb 2018 14:27:13 +0200 Subject: [PATCH 106/392] can: xilinx_can: fix RX overflow interrupt not being enabled commit 83997997252f5d3fc7f04abc24a89600c2b504ab upstream. RX overflow interrupt (RXOFLW) is disabled even though xcan_interrupt() processes it. This means that an RX overflow interrupt will only be processed when another interrupt gets asserted (e.g. for RX/TX). Fix that by enabling the RXOFLW interrupt. Fixes: b1201e44f50b ("can: xilinx CAN controller support") Signed-off-by: Anssi Hannula Cc: Michal Simek Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/xilinx_can.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index fd557e7a4410..8ca23539c23a 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -102,7 +102,7 @@ enum xcan_reg { #define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ - XCAN_IXR_ARBLST_MASK) + XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ARBLST_MASK) /* CAN register bit shift - XCAN___SHIFT */ #define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ From 3a71ae0513c232c844009738af135a13e5d7e39c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 26 Jul 2018 10:13:23 +0200 Subject: [PATCH 107/392] ARM: fix put_user() for gcc-8 Building kernels before linux-4.7 with gcc-8 results in many build failures when gcc triggers a check that was meant to catch broken compilers: /tmp/ccCGMQmS.s:648: Error: .err encountered According to the discussion in the gcc bugzilla, a local "register asm()" variable is still supposed to be the correct way to force an inline assembly to use a particular register, but marking it 'const' lets the compiler do optimizations that break that, i.e the compiler is free to treat the variable as either 'const' or 'register' in that case. Upstream commit 9f73bd8bb445 ("ARM: uaccess: remove put_user() code duplication") fixed this problem in linux-4.8 as part of a larger change, but seems a little too big to be backported to 4.4. Let's take the simplest fix and change only the one broken line in the same way as newer kernels. Suggested-by: Bernd Edlinger Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85745 Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86673 Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 4767eb9caa78..69b6c3f125c2 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -220,7 +220,7 @@ extern int __put_user_8(void *, unsigned long long); ({ \ unsigned long __limit = current_thread_info()->addr_limit - 1; \ const typeof(*(p)) __user *__tmp_p = (p); \ - register const typeof(*(p)) __r2 asm("r2") = (x); \ + register typeof(*(p)) __r2 asm("r2") = (x); \ register const typeof(*(p)) __user *__p asm("r0") = __tmp_p; \ register unsigned long __l asm("r1") = __limit; \ register int __e asm("r0"); \ From 430c3fdb11ec1f0af1eca28460c922b9c1eb2ac5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 26 Jul 2018 10:13:22 +0200 Subject: [PATCH 108/392] turn off -Wattribute-alias Starting with gcc-8.1, we get a warning about all system call definitions, which use an alias between functions with incompatible prototypes, e.g.: In file included from ../mm/process_vm_access.c:19: ../include/linux/syscalls.h:211:18: warning: 'sys_process_vm_readv' alias between functions of incompatible types 'long int(pid_t, const struct iovec *, long unsigned int, const struct iovec *, long unsigned int, long unsigned int)' {aka 'long int(int, const struct iovec *, long unsigned int, const struct iovec *, long unsigned int, long unsigned int)'} and 'long int(long int, long int, long int, long int, long int, long int)' [-Wattribute-alias] asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ ^~~ ../include/linux/syscalls.h:207:2: note: in expansion of macro '__SYSCALL_DEFINEx' __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) ^~~~~~~~~~~~~~~~~ ../include/linux/syscalls.h:201:36: note: in expansion of macro 'SYSCALL_DEFINEx' #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) ^~~~~~~~~~~~~~~ ../mm/process_vm_access.c:300:1: note: in expansion of macro 'SYSCALL_DEFINE6' SYSCALL_DEFINE6(process_vm_readv, pid_t, pid, const struct iovec __user *, lvec, ^~~~~~~~~~~~~~~ ../include/linux/syscalls.h:215:18: note: aliased declaration here asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ ^~~ ../include/linux/syscalls.h:207:2: note: in expansion of macro '__SYSCALL_DEFINEx' __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) ^~~~~~~~~~~~~~~~~ ../include/linux/syscalls.h:201:36: note: in expansion of macro 'SYSCALL_DEFINEx' #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) ^~~~~~~~~~~~~~~ ../mm/process_vm_access.c:300:1: note: in expansion of macro 'SYSCALL_DEFINE6' SYSCALL_DEFINE6(process_vm_readv, pid_t, pid, const struct iovec __user *, lvec, This is really noisy and does not indicate a real problem. In the latest mainline kernel, this was addressed by commit bee20031772a ("disable -Wattribute-alias warning for SYSCALL_DEFINEx()"), which seems too invasive to backport. This takes a much simpler approach and just disables the warning across the kernel. Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 973e8568e52d..be606849c99a 100644 --- a/Makefile +++ b/Makefile @@ -613,6 +613,7 @@ KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,) KBUILD_CFLAGS += $(call cc-disable-warning, format-truncation) KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow) KBUILD_CFLAGS += $(call cc-disable-warning, int-in-bool-context) +KBUILD_CFLAGS += $(call cc-disable-warning, attribute-alias) KBUILD_CFLAGS += $(call cc-option,-fno-PIE) KBUILD_AFLAGS += $(call cc-option,-fno-PIE) From dbba166b0e442d4d38ae0f244d32338c3e92d16f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 28 Jul 2018 07:43:19 +0200 Subject: [PATCH 109/392] Linux 3.18.117 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index be606849c99a..9c894e7e586d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 18 -SUBLEVEL = 116 +SUBLEVEL = 117 EXTRAVERSION = NAME = Diseased Newt From 3ede52c38a010edbee4310d801f589cfeb606bc4 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Fri, 6 Jul 2018 16:08:12 +0530 Subject: [PATCH 110/392] msm: camera: Fix out-of-bounds read in string class name. jpeg driver is calling class_create with stack variable, which can be overwritten by other stack variables. Change-Id: I3c22a5b3375b970ff6b1c6de983dd5833f4e11d0 Signed-off-by: Trishansh Bhardwaj --- drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c index de27e585f63d..48f53f171da1 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c @@ -32,6 +32,8 @@ #define MSM_JPEG_NAME "jpeg" #define DEV_NAME_LEN 10 +static char devname[DEV_NAME_LEN]; + static int msm_jpeg_open(struct inode *inode, struct file *filp) { int rc = 0; @@ -185,7 +187,6 @@ static int msm_jpeg_init_dev(struct platform_device *pdev) struct msm_jpeg_device *msm_jpeg_device_p; const struct of_device_id *device_id; const struct msm_jpeg_priv_data *priv_data; - char devname[DEV_NAME_LEN]; msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC); if (!msm_jpeg_device_p) { From d882e831c0515ff4a63628991e014a7f3d7eb9be Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Sun, 1 Jul 2018 12:08:59 +0530 Subject: [PATCH 111/392] msm: mdss: use uaccess routines to access user space buffers Use routines defined in uaccess.h (like put_user, get_user) while accessing user space buffers. Otherwise this leads to userspace access violation when PAN is enabled. Change-Id: Iea16e347ee71f0845711a21b6b9b01e16a6ab619 Signed-off-by: Nirmal Abraham --- drivers/video/msm/mdss/mdss_compat_utils.c | 150 ++++++++++++--------- 1 file changed, 87 insertions(+), 63 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_compat_utils.c b/drivers/video/msm/mdss/mdss_compat_utils.c index 558c2d7c1dde..7a93d292a6da 100644 --- a/drivers/video/msm/mdss/mdss_compat_utils.c +++ b/drivers/video/msm/mdss/mdss_compat_utils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * Copyright (C) 1994 Martin Schaller * * 2001 - Documented with DocBook @@ -2878,26 +2878,28 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, *pp = compat_alloc_user_space(alloc_size); if (NULL == *pp) return -ENOMEM; - memset(*pp, 0, alloc_size); - - (*pp)->data.lut_cfg_data.data.pgc_lut_data.r_data = - (struct mdp_ar_gc_lut_data *) - ((unsigned long) *pp + - sizeof(struct msmfb_mdp_pp)); - (*pp)->data.lut_cfg_data.data.pgc_lut_data.g_data = - (struct mdp_ar_gc_lut_data *) + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((struct mdp_ar_gc_lut_data *) + ((unsigned long) *pp + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.lut_cfg_data.data.pgc_lut_data.r_data) || + put_user((struct mdp_ar_gc_lut_data *) ((unsigned long) *pp + sizeof(struct msmfb_mdp_pp) + - pgc_size); - (*pp)->data.lut_cfg_data.data.pgc_lut_data.b_data = - (struct mdp_ar_gc_lut_data *) + pgc_size), + &(*pp)->data.lut_cfg_data.data.pgc_lut_data.g_data) || + put_user((struct mdp_ar_gc_lut_data *) ((unsigned long) *pp + sizeof(struct msmfb_mdp_pp) + - (2 * pgc_size)); - (*pp)->data.lut_cfg_data.data.pgc_lut_data.cfg_payload - = (void *)((unsigned long) *pp + + (2 * pgc_size)), + &(*pp)->data.lut_cfg_data.data.pgc_lut_data.b_data) || + put_user((void *)((unsigned long) *pp + sizeof(struct msmfb_mdp_pp) + - (3 * pgc_size)); + (3 * pgc_size)), + &(*pp)->data.lut_cfg_data.data. + pgc_lut_data.cfg_payload)) + return -EFAULT; break; case mdp_lut_igc: alloc_size += __pp_compat_size_igc(); @@ -2907,10 +2909,13 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.lut_cfg_data.data.igc_lut_data.cfg_payload - = (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.lut_cfg_data.data. + igc_lut_data.cfg_payload)) + return -EFAULT; break; case mdp_lut_hist: alloc_size += __pp_compat_size_hist_lut(); @@ -2920,10 +2925,13 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.lut_cfg_data.data.hist_lut_data.cfg_payload - = (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.lut_cfg_data.data. + hist_lut_data.cfg_payload)) + return -EFAULT; break; default: *pp = compat_alloc_user_space(alloc_size); @@ -2932,7 +2940,8 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size, lut_type); return -ENOMEM; } - memset(*pp, 0, alloc_size); + if (clear_user(*pp, alloc_size)) + return -EFAULT; break; } break; @@ -2944,10 +2953,12 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.pcc_cfg_data.cfg_payload = - (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.pcc_cfg_data.cfg_payload)) + return -EFAULT; break; case mdp_op_gamut_cfg: alloc_size += __pp_compat_size_gamut(); @@ -2957,10 +2968,12 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.gamut_cfg_data.cfg_payload = - (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.gamut_cfg_data.cfg_payload)) + return -EFAULT; break; case mdp_op_pa_v2_cfg: alloc_size += __pp_compat_size_pa(); @@ -2970,16 +2983,19 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.pa_v2_cfg_data.cfg_payload = - (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.pa_v2_cfg_data.cfg_payload)) + return -EFAULT; break; default: *pp = compat_alloc_user_space(alloc_size); if (NULL == *pp) return -ENOMEM; - memset(*pp, 0, alloc_size); + if (clear_user(*pp, alloc_size)) + return -EFAULT; break; } return 0; @@ -3397,7 +3413,9 @@ static int mdss_histo_compat_ioctl(struct fb_info *info, unsigned int cmd, sizeof(struct mdp_histogram_start_req)); return -EINVAL; } - memset(hist_req, 0, sizeof(struct mdp_histogram_start_req)); + if (clear_user(hist_req, + sizeof(struct mdp_histogram_start_req))) + return -EFAULT; ret = __from_user_hist_start_req(hist_req32, hist_req); if (ret) goto histo_compat_err; @@ -3417,7 +3435,8 @@ static int mdss_histo_compat_ioctl(struct fb_info *info, unsigned int cmd, sizeof(struct mdp_histogram_data)); return -EINVAL; } - memset(hist, 0, sizeof(struct mdp_histogram_data)); + if (clear_user(hist, sizeof(struct mdp_histogram_data))) + return -EFAULT; ret = __from_user_hist_data(hist32, hist); if (ret) goto histo_compat_err; @@ -3920,7 +3939,7 @@ static int __to_user_mdp_overlay(struct mdp_overlay32 __user *ov32, } -static int __from_user_mdp_overlay(struct mdp_overlay *ov, +static int __from_user_mdp_overlay(struct mdp_overlay __user *ov, struct mdp_overlay32 __user *ov32) { __u32 data; @@ -3979,12 +3998,12 @@ static int __from_user_mdp_overlay(struct mdp_overlay *ov, return 0; } -static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, - struct mdp_overlay_list32 *ovlist32, +static int __from_user_mdp_overlaylist(struct mdp_overlay_list __user *ovlist, + struct mdp_overlay_list32 __user *ovlist32, struct mdp_overlay **to_list_head) { __u32 i, ret; - unsigned long data, from_list_head; + unsigned long data, from_list_head, num_overlays; struct mdp_overlay32 *iter; if (!to_list_head || !ovlist32 || !ovlist) { @@ -4005,11 +4024,13 @@ static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, sizeof(ovlist32->processed_overlays))) return -EFAULT; - if (get_user(data, &ovlist32->overlay_list)) { + if (get_user(data, &ovlist32->overlay_list) || + get_user(num_overlays, &ovlist32->num_overlays)) { ret = -EFAULT; goto validate_exit; } - for (i = 0; i < ovlist32->num_overlays; i++) { + + for (i = 0; i < num_overlays; i++) { if (get_user(from_list_head, (__u32 *)data + i)) { ret = -EFAULT; goto validate_exit; @@ -4022,7 +4043,8 @@ static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, goto validate_exit; } } - ovlist->overlay_list = to_list_head; + if (put_user(to_list_head, &ovlist->overlay_list)) + return -EFAULT; return 0; @@ -4031,8 +4053,8 @@ static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, return -EFAULT; } -static int __to_user_mdp_overlaylist(struct mdp_overlay_list32 *ovlist32, - struct mdp_overlay_list *ovlist, +static int __to_user_mdp_overlaylist(struct mdp_overlay_list32 __user *ovlist32, + struct mdp_overlay_list __user *ovlist, struct mdp_overlay **l_ptr) { __u32 i, ret; @@ -4105,31 +4127,33 @@ static u32 __pp_sspp_size(void) return size; } -static int __pp_sspp_set_offsets(struct mdp_overlay *ov) +static int __pp_sspp_set_offsets(struct mdp_overlay __user *ov) { if (!ov) { pr_err("invalid overlay pointer\n"); return -EFAULT; } - ov->overlay_pp_cfg.igc_cfg.cfg_payload = (void *)((unsigned long)ov + - sizeof(struct mdp_overlay)); - ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload = - ov->overlay_pp_cfg.igc_cfg.cfg_payload + - sizeof(struct mdp_igc_lut_data_v1_7); - ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload = - ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload + - sizeof(struct mdp_pa_data_v1_7); - ov->overlay_pp_cfg.hist_lut_cfg.cfg_payload = - ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload + - sizeof(struct mdp_pcc_data_v1_7); + if (put_user((void *)((unsigned long)ov + sizeof(struct mdp_overlay)), + &(ov->overlay_pp_cfg.igc_cfg.cfg_payload)) || + put_user(ov->overlay_pp_cfg.igc_cfg.cfg_payload + + sizeof(struct mdp_igc_lut_data_v1_7), + &(ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload)) || + put_user(ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload + + sizeof(struct mdp_pa_data_v1_7), + &(ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload)) || + put_user(ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload + + sizeof(struct mdp_pcc_data_v1_7), + &(ov->overlay_pp_cfg.hist_lut_cfg.cfg_payload))) + return -EFAULT; return 0; } int mdss_compat_overlay_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg, struct file *file) { - struct mdp_overlay *ov, **layers_head; - struct mdp_overlay32 *ov32; + struct mdp_overlay **layers_head; + struct mdp_overlay __user *ov; + struct mdp_overlay32 __user *ov32; struct mdp_overlay_list __user *ovlist; struct mdp_overlay_list32 __user *ovlist32; size_t layers_refs_sz, layers_sz, prepare_sz; From cf1d9e143a94f548076c7fb8a9287699d941cfe0 Mon Sep 17 00:00:00 2001 From: Balachandra C S Date: Mon, 7 May 2018 15:08:42 +0530 Subject: [PATCH 112/392] drivers: net: can: Add END_FW_UPDATE_FILE command to qti-can driver Add IOCTL command to indicate the controller that firmware update file end of file is reached. Change-Id: Ib538ff68a4b974234ce541696d38772e7065b7d8 Signed-off-by: Balachandra C S --- drivers/net/can/spi/qti-can.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/can/spi/qti-can.c b/drivers/net/can/spi/qti-can.c index 253e341dbb58..cf979d90ec40 100644 --- a/drivers/net/can/spi/qti-can.c +++ b/drivers/net/can/spi/qti-can.c @@ -118,6 +118,7 @@ struct spi_miso { /* TLV for MISO line */ #define CMD_BEGIN_BOOT_ROM_UPGRADE 0x99 #define CMD_BOOT_ROM_UPGRADE_DATA 0x9A #define CMD_END_BOOT_ROM_UPGRADE 0x9B +#define CMD_END_FW_UPDATE_FILE 0x9C #define IOCTL_RELEASE_CAN_BUFFER (SIOCDEVPRIVATE + 0) #define IOCTL_ENABLE_BUFFERING (SIOCDEVPRIVATE + 1) @@ -132,6 +133,7 @@ struct spi_miso { /* TLV for MISO line */ #define IOCTL_BEGIN_BOOT_ROM_UPGRADE (SIOCDEVPRIVATE + 11) #define IOCTL_BOOT_ROM_UPGRADE_DATA (SIOCDEVPRIVATE + 12) #define IOCTL_END_BOOT_ROM_UPGRADE (SIOCDEVPRIVATE + 13) +#define IOCTL_END_FW_UPDATE_FILE (SIOCDEVPRIVATE + 14) #define IFR_DATA_OFFSET 0x100 struct can_fw_resp { @@ -983,6 +985,8 @@ static int qti_can_convert_ioctl_cmd_to_spi_cmd(int ioctl_cmd) return CMD_BOOT_ROM_UPGRADE_DATA; case IOCTL_END_BOOT_ROM_UPGRADE: return CMD_END_BOOT_ROM_UPGRADE; + case IOCTL_END_FW_UPDATE_FILE: + return CMD_END_FW_UPDATE_FILE; } return -EINVAL; } @@ -1119,6 +1123,7 @@ static int qti_can_netdev_do_ioctl(struct net_device *netdev, case IOCTL_BEGIN_BOOT_ROM_UPGRADE: case IOCTL_BOOT_ROM_UPGRADE_DATA: case IOCTL_END_BOOT_ROM_UPGRADE: + case IOCTL_END_FW_UPDATE_FILE: ret = qti_can_do_blocking_ioctl(netdev, ifr, cmd); break; } From b9fd7441c937207063fcc129153c52c30feadeef Mon Sep 17 00:00:00 2001 From: Balachandra C S Date: Thu, 24 May 2018 19:46:25 +0530 Subject: [PATCH 113/392] drivers: net: can: Add timestamp adjustment for frames in qti-can Correct the frame timestamp based on the controller and host time difference. Change-Id: I6c60b943d18779a9bd9f221a2344dcea90b9fb5a Signed-off-by: Balachandra C S --- drivers/net/can/spi/qti-can.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/spi/qti-can.c b/drivers/net/can/spi/qti-can.c index cf979d90ec40..866761428213 100644 --- a/drivers/net/can/spi/qti-can.c +++ b/drivers/net/can/spi/qti-can.c @@ -70,6 +70,7 @@ struct qti_can { bool can_fw_cmd_timeout_req; u32 rem_all_buffering_timeout_ms; u32 can_fw_cmd_timeout_ms; + s64 time_diff; }; struct qti_can_netdev_privdata { @@ -119,6 +120,7 @@ struct spi_miso { /* TLV for MISO line */ #define CMD_BOOT_ROM_UPGRADE_DATA 0x9A #define CMD_END_BOOT_ROM_UPGRADE 0x9B #define CMD_END_FW_UPDATE_FILE 0x9C +#define CMD_UPDATE_TIME_INFO 0x9D #define IOCTL_RELEASE_CAN_BUFFER (SIOCDEVPRIVATE + 0) #define IOCTL_ENABLE_BUFFERING (SIOCDEVPRIVATE + 1) @@ -165,7 +167,7 @@ struct can_add_filter_resp { struct can_receive_frame { u8 can_if; - u32 ts; + u64 ts; u32 mid; u8 dlc; u8 data[8]; @@ -180,6 +182,10 @@ struct can_config_bit_timing { u32 brp; } __packed; +struct can_time_info { + u64 time; +} __packed; + static struct can_bittiming_const rh850_bittiming_const = { .name = "qti_can", .tseg1_min = 1, @@ -293,7 +299,7 @@ static void qti_can_receive_frame(struct qti_can *priv_data, return; } - LOGDI("rcv frame %d %d %x %d %x %x %x %x %x %x %x %x\n", + LOGDI("rcv frame %d %llu %x %d %x %x %x %x %x %x %x %x\n", frame->can_if, frame->ts, frame->mid, frame->dlc, frame->data[0], frame->data[1], frame->data[2], frame->data[3], frame->data[4], frame->data[5], frame->data[6], frame->data[7]); @@ -303,7 +309,8 @@ static void qti_can_receive_frame(struct qti_can *priv_data, for (i = 0; i < cf->can_dlc; i++) cf->data[i] = frame->data[i]; - nsec = ms_to_ktime(le32_to_cpu(frame->ts)); + nsec = ms_to_ktime(le64_to_cpu(frame->ts) + priv_data->time_diff); + skt = skb_hwtstamps(skb); skt->hwtstamp = nsec; LOGDI(" hwtstamp %lld\n", ktime_to_ms(skt->hwtstamp)); @@ -356,6 +363,8 @@ static int qti_can_process_response(struct qti_can *priv_data, struct spi_miso *resp, int length) { int ret = 0; + u64 mstime; + ktime_t ktime_now; LOGDI("<%x %2d [%d]\n", resp->cmd, resp->len, resp->seq); if (resp->cmd == CMD_CAN_RECEIVE_FRAME) { @@ -404,6 +413,12 @@ static int qti_can_process_response(struct qti_can *priv_data, ret |= (fw_resp->br_min & 0xFF) << 16; ret |= (fw_resp->maj & 0xF) << 8; ret |= (fw_resp->min & 0xFF); + } else if (resp->cmd == CMD_UPDATE_TIME_INFO) { + struct can_time_info *time_data = + (struct can_time_info *)resp->data; + ktime_now = ktime_get_boottime(); + mstime = ktime_to_ms(ktime_now); + priv_data->time_diff = mstime - (le64_to_cpu(time_data->time)); } if (resp->cmd == priv_data->wait_cmd) { From 9fd6fa06aadb48c43edcf4590b9c7db78b51afaa Mon Sep 17 00:00:00 2001 From: Balachandra C S Date: Wed, 6 Jun 2018 17:05:23 +0530 Subject: [PATCH 114/392] ARM: dts: msm: Add proper interrupt type in device tree Irq type may vary among targets, add proper interrupt type in device tree for gpio interrupt from CAN controller for MDM9650, APQ8096 and MSM8996. Change-Id: I08c0d73bcbf24ae4611b62ae843a05536d828872 Signed-off-by: Balachandra C S --- arch/arm/boot/dts/qcom/apq8096-v2-auto-dragonboard.dts | 2 +- arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts | 2 +- arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts | 2 +- arch/arm/boot/dts/qcom/apq8096-v3-auto-dragonboard.dts | 2 +- arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts | 2 +- arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts | 2 +- arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts | 2 +- arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi | 2 +- arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts | 2 +- arch/arm/boot/dts/qcom/msm8996-v3-auto-cdp.dts | 2 +- arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp.dts | 2 +- arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts | 2 +- arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts | 2 +- arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/arm/boot/dts/qcom/apq8096-v2-auto-dragonboard.dts b/arch/arm/boot/dts/qcom/apq8096-v2-auto-dragonboard.dts index c21b6d6cbc9e..a30813f4be6c 100644 --- a/arch/arm/boot/dts/qcom/apq8096-v2-auto-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/apq8096-v2-auto-dragonboard.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts b/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts index 74bb21eedf10..0f021e0ef437 100644 --- a/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <122 0>; + interrupts = <122 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts index 82030c493f8d..4e683f632894 100644 --- a/arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/apq8096-v3-auto-cdp.dts @@ -38,7 +38,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096-v3-auto-dragonboard.dts b/arch/arm/boot/dts/qcom/apq8096-v3-auto-dragonboard.dts index cd02dacbdcee..2be4f89c0cc7 100644 --- a/arch/arm/boot/dts/qcom/apq8096-v3-auto-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/apq8096-v3-auto-dragonboard.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts index e2d4f2b9babe..fa0da0c23743 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts index fdea81eb9322..3ee3238bae7b 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts @@ -31,7 +31,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <122 0>; + interrupts = <122 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts index d5eb6031e378..15bd28865e64 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi b/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi index 3ab680127d64..c32278a35ad1 100644 --- a/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9650-ccard.dtsi @@ -613,7 +613,7 @@ reg = <0>; spi-max-frequency = <9600000>; interrupt-parent = <&tlmm_pinmux>; - interrupts = <87 0>; + interrupts = <87 2>; qcom,reset-gpio = <&tlmm_pinmux 89 0x1>; qcom,clk-freq-mhz = <20000000>; qcom,max-can-channels = <1>; diff --git a/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts b/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts index d4cf58f9b8ea..4ff449a45d1a 100644 --- a/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts @@ -31,7 +31,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <122 0>; + interrupts = <122 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/msm8996-v3-auto-cdp.dts b/arch/arm/boot/dts/qcom/msm8996-v3-auto-cdp.dts index 33daf9d6f0e7..250ce9289c70 100644 --- a/arch/arm/boot/dts/qcom/msm8996-v3-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/msm8996-v3-auto-cdp.dts @@ -43,7 +43,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp.dts b/arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp.dts index d84b0d781b29..cf1128b5d283 100644 --- a/arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp.dts +++ b/arch/arm/boot/dts/qcom/msm8996-v3-pm8004-agave-adp.dts @@ -28,7 +28,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <122 0>; + interrupts = <122 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts index 15b00af5f0f4..91f9ab654e51 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts @@ -31,7 +31,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <122 0>; + interrupts = <122 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts index 4a78a2fef835..a4c0a0515995 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-cdp.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts b/arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts index d75f56d12291..13a0e914cdfa 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/msm8996pro-v1.1-auto-cdp.dts @@ -30,7 +30,7 @@ compatible = "qcom,renesas,rh850"; reg = <0>; interrupt-parent = <&tlmm>; - interrupts = <127 0>; + interrupts = <127 2>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <16000000>; qcom,max-can-channels = <4>; From 637cff3c2df401c81b3bb49752b08a73441337bd Mon Sep 17 00:00:00 2001 From: Balachandra C S Date: Sun, 8 Jul 2018 22:40:20 +0530 Subject: [PATCH 115/392] drivers: net: can: Use interrupt type from device tree Use proper interrupt type from the device tree for gpio interrupt from CAN controller in qti-can driver as irq type may vary with different targets. Change-Id: If08c3f6d53fc6e8b7a55be47705c5a1841c0c913 Signed-off-by: Balachandra C S --- drivers/net/can/spi/qti-can.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/spi/qti-can.c b/drivers/net/can/spi/qti-can.c index 866761428213..ae1b9c9b512c 100644 --- a/drivers/net/can/spi/qti-can.c +++ b/drivers/net/can/spi/qti-can.c @@ -1263,6 +1263,7 @@ static int qti_can_probe(struct spi_device *spi) int err, retry = 0, query_err = -1, i; struct qti_can *priv_data = NULL; struct device *dev; + u32 irq_type; dev = &spi->dev; dev_info(dev, "qti_can_probe"); @@ -1369,8 +1370,11 @@ static int qti_can_probe(struct spi_device *spi) } } + irq_type = irq_get_trigger_type(spi->irq); + if (irq_type == IRQ_TYPE_NONE) + irq_type = IRQ_TYPE_EDGE_FALLING; err = request_threaded_irq(spi->irq, NULL, qti_can_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + irq_type | IRQF_ONESHOT, "qti-can", priv_data); if (err) { LOGDE("Failed to request irq: %d", err); From 807cbc88de6312efac142e63b990a5aa88bde120 Mon Sep 17 00:00:00 2001 From: Balachandra C S Date: Wed, 4 Jul 2018 16:26:53 +0530 Subject: [PATCH 116/392] drivers: net: can: Use proper device property in qti-can driver Use the proper device tree property in qti-can driver for enabling can-fd feature. Change-Id: I4c59e7037a8e0f4972603aceb65138a190080074 Signed-off-by: Balachandra C S --- drivers/net/can/spi/qti-can.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/spi/qti-can.c b/drivers/net/can/spi/qti-can.c index ae1b9c9b512c..9ffa7e9b3041 100644 --- a/drivers/net/can/spi/qti-can.c +++ b/drivers/net/can/spi/qti-can.c @@ -1340,7 +1340,7 @@ static int qti_can_probe(struct spi_device *spi) } priv_data->support_can_fd = of_property_read_bool(spi->dev.of_node, - "support-can-fd"); + "qcom,support-can-fd"); if (of_device_is_compatible(spi->dev.of_node, "qcom,nxp,mpc5746c")) qti_can_bittiming_const = flexcan_bittiming_const; From bb7834d0add21791d19c6a8432b6b3dd63f87389 Mon Sep 17 00:00:00 2001 From: Balachandra C S Date: Mon, 9 Jul 2018 17:24:41 +0530 Subject: [PATCH 117/392] drivers: net: can: Inform power states to CAN controller CAN controller needs to be aware of host power state to decide if timestamp message can be sent to host or not. Change-Id: I89a570a2fb38336c38d0105bbb3df8b89d7e3035 Signed-off-by: Balachandra C S --- drivers/net/can/spi/qti-can.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/spi/qti-can.c b/drivers/net/can/spi/qti-can.c index 9ffa7e9b3041..27bd2fe2edff 100644 --- a/drivers/net/can/spi/qti-can.c +++ b/drivers/net/can/spi/qti-can.c @@ -121,6 +121,8 @@ struct spi_miso { /* TLV for MISO line */ #define CMD_END_BOOT_ROM_UPGRADE 0x9B #define CMD_END_FW_UPDATE_FILE 0x9C #define CMD_UPDATE_TIME_INFO 0x9D +#define CMD_SUSPEND_EVENT 0x9E +#define CMD_RESUME_EVENT 0x9F #define IOCTL_RELEASE_CAN_BUFFER (SIOCDEVPRIVATE + 0) #define IOCTL_ENABLE_BUFFERING (SIOCDEVPRIVATE + 1) @@ -580,6 +582,30 @@ static int qti_can_query_firmware_version(struct qti_can *priv_data) return ret; } +static int qti_can_notify_power_events(struct qti_can *priv_data, u8 event_type) +{ + char *tx_buf, *rx_buf; + int ret; + struct spi_mosi *req; + + mutex_lock(&priv_data->spi_lock); + tx_buf = priv_data->tx_buf; + rx_buf = priv_data->rx_buf; + memset(tx_buf, 0, XFER_BUFFER_SIZE); + memset(rx_buf, 0, XFER_BUFFER_SIZE); + priv_data->xfer_length = XFER_BUFFER_SIZE; + + req = (struct spi_mosi *)tx_buf; + req->cmd = event_type; + req->len = 0; + req->seq = atomic_inc_return(&priv_data->msg_seq); + + ret = qti_can_do_spi_transaction(priv_data); + mutex_unlock(&priv_data->spi_lock); + + return ret; +} + static int qti_can_set_bitrate(struct net_device *netdev) { char *tx_buf, *rx_buf; @@ -1440,6 +1466,10 @@ static int qti_can_remove(struct spi_device *spi) static int qti_can_suspend(struct device *dev) { struct spi_device *spi = to_spi_device(dev); + struct qti_can *priv_data = spi_get_drvdata(spi); + u8 power_event = CMD_SUSPEND_EVENT; + + qti_can_notify_power_events(priv_data, power_event); enable_irq_wake(spi->irq); return 0; @@ -1449,9 +1479,10 @@ static int qti_can_resume(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct qti_can *priv_data = spi_get_drvdata(spi); + u8 power_event = CMD_RESUME_EVENT; disable_irq_wake(spi->irq); - qti_can_rx_message(priv_data); + qti_can_notify_power_events(priv_data, power_event); return 0; } From 4b89bdea69995195c7ca38d545cd9d8304901120 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Mon, 21 May 2018 19:00:49 +0530 Subject: [PATCH 118/392] msm: mhi_dev: Fix incorrect transfer size in completion event Set the correct transfer size instead of the TRE size when sending completion event to host in mhi_dev_transfer_completion_cb. Also, do not access the MHI transfer request structure after the client callback has been called since it may be re-used for other transfers. Copy the required fields locally instead. Change-Id: I6b2cbec3bb3ebfaead926054077e6c0bca85b90e Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 056c999bcfbf..6800ce023e8e 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -1406,16 +1406,20 @@ static void mhi_dev_transfer_completion_cb(void *mreq) union mhi_dev_ring_element_type *el; int rc = 0; struct mhi_req *req = (struct mhi_req *)mreq; - struct mhi_req *local_req = NULL; union mhi_dev_ring_element_type *compl_ev = NULL; struct mhi_dev *mhi = NULL; unsigned long flags; + size_t transfer_len; + u32 snd_cmpl; + uint32_t rd_offset; client = req->client; ch = client->channel; mhi = ch->ring->mhi_dev; el = req->el; - local_req = req; + transfer_len = req->len; + snd_cmpl = req->snd_cmpl; + rd_offset = req->rd_offset; ch->curr_ereq->context = ch; dma_unmap_single(&mhi_ctx->pdev->dev, req->dma, @@ -1429,14 +1433,13 @@ static void mhi_dev_transfer_completion_cb(void *mreq) compl_ev->evt_tr_comp.chid = ch->ch_id; compl_ev->evt_tr_comp.type = MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT; - compl_ev->evt_tr_comp.len = el->tre.len; + compl_ev->evt_tr_comp.len = transfer_len; compl_ev->evt_tr_comp.code = MHI_CMD_COMPL_CODE_EOT; compl_ev->evt_tr_comp.ptr = ch->ring->ring_ctx->generic.rbase + - local_req->rd_offset * TR_RING_ELEMENT_SZ; + rd_offset * TR_RING_ELEMENT_SZ; ch->curr_ereq->num_events++; - if (ch->curr_ereq->num_events >= MAX_TR_EVENTS || - local_req->snd_cmpl){ + if (ch->curr_ereq->num_events >= MAX_TR_EVENTS || snd_cmpl) { mhi_log(MHI_MSG_VERBOSE, "num of tr events %d for ch %d\n", ch->curr_ereq->num_events, ch->ch_id); From e0d81edbf9a4cb29400035a3658d823e82833bd8 Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Mon, 23 Jul 2018 12:48:28 +0530 Subject: [PATCH 119/392] ASoC: msm: qdsp6v2: Fix uninitialized variable error Variable is used without initializing, initialize it to proper value. CRs-Fixed: 2273335 Change-Id: I8c37babe5f56c68acbce60c11c3d595333f22868 Signed-off-by: Dhanalakshmi Siddani --- sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 996175674910..e505f416ab2c 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -293,7 +293,7 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) struct msm_audio *prtd = runtime->private_data; struct msm_plat_data *pdata; struct snd_pcm_hw_params *params; - int ret; + int ret = 0; uint16_t bits_per_sample; uint16_t sample_word_size; From 31e82d61961a1214cfd4a6424d4fc0cba1562ff3 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Thu, 5 Jul 2018 10:55:32 +0530 Subject: [PATCH 120/392] msm: sps: Suppress bind/unbind attributes SPS driver does not support manual bind/unbind operations through sysfs. Suppress the bind/unbind nodes. Do not free SPS struct in sps_device_de_init since it is being done in sps_exit, and also to avoid use-after-free. Change-Id: If6da6c5fb9d1a44d0420c6151f7f9d0a33cb2d04 Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/sps/sps.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c index 03cc14aa7e29..2237db198c53 100644 --- a/drivers/platform/msm/sps/sps.c +++ b/drivers/platform/msm/sps/sps.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1006,8 +1006,6 @@ static void sps_device_de_init(void) "sps:%s:BAMs are still registered", __func__); sps_map_de_init(); - - kfree(sps); } sps_mem_de_init(); @@ -2989,6 +2987,7 @@ static struct platform_driver msm_sps_driver = { .name = SPS_DRV_NAME, .owner = THIS_MODULE, .of_match_table = msm_sps_match, + .suppress_bind_attrs = true, }, .remove = msm_sps_remove, }; From 9afe611992d40d23659983832fb8bbbf13548717 Mon Sep 17 00:00:00 2001 From: Arun Kumar Neelakantam Date: Thu, 19 Jul 2018 14:25:22 +0530 Subject: [PATCH 121/392] net: ipc_router: Initialize the sockaddr in recvmsg() handler sockaddr structure is filled with required information only which results in few memory locations of structure with uninitialized data. Memset complete structure before using it to remove uninitialized data. CRs-Fixed: 2274853 Change-Id: I181710bde100fb1553b925d9fdf227af35ff38b5 Signed-off-by: Arun Kumar Neelakantam --- net/ipc_router/ipc_router_socket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipc_router/ipc_router_socket.c b/net/ipc_router/ipc_router_socket.c index 8604152dc577..1641509c9352 100644 --- a/net/ipc_router/ipc_router_socket.c +++ b/net/ipc_router/ipc_router_socket.c @@ -155,6 +155,7 @@ static int msm_ipc_router_extract_msg(struct msghdr *m, return -EINVAL; } ctl_msg = (union rr_control_msg *)(temp->data); + memset(addr, 0x0, sizeof(*addr)); addr->family = AF_MSM_IPC; addr->address.addrtype = MSM_IPC_ADDR_ID; addr->address.addr.port_addr.node_id = ctl_msg->cli.node_id; @@ -163,6 +164,7 @@ static int msm_ipc_router_extract_msg(struct msghdr *m, return offset; } if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_DATA)) { + memset(addr, 0x0, sizeof(*addr)); addr->family = AF_MSM_IPC; addr->address.addrtype = MSM_IPC_ADDR_ID; addr->address.addr.port_addr.node_id = hdr->src_node_id; From 12ed91a6c251d808800290bd6325c1a82020ae0b Mon Sep 17 00:00:00 2001 From: Sachin Grover Date: Thu, 24 May 2018 22:48:55 +0530 Subject: [PATCH 122/392] selinux: KASAN: slab-out-of-bounds in xattr_getsecurity Call trace: [] dump_backtrace+0x0/0x428 [] show_stack+0x28/0x38 [] dump_stack+0xd4/0x124 [] print_address_description+0x68/0x258 [] kasan_report.part.2+0x228/0x2f0 [] kasan_report+0x5c/0x70 [] check_memory_region+0x12c/0x1c0 [] memcpy+0x34/0x68 [] xattr_getsecurity+0xe0/0x160 [] vfs_getxattr+0xc8/0x120 [] getxattr+0x100/0x2c8 [] SyS_fgetxattr+0x64/0xa0 [] el0_svc_naked+0x24/0x28 If user get root access and calls security.selinux setxattr() with an embedded NUL on a file and then if some process performs a getxattr() on that file with a length greater than the actual length of the string, it would result in a panic. To fix this, add the actual length of the string to the security context instead of the length passed by the userspace process. Change-Id: Ie0b8bfc7c96bc12282b955fb3adf41b3c2d011cd Signed-off-by: Sachin Grover --- security/selinux/ss/services.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 4719b109eaa0..015e61e6e2d1 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1443,7 +1443,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, scontext_len, &context, def_sid); if (rc == -EINVAL && force) { context.str = str; - context.len = scontext_len; + context.len = strlen(str) + 1; str = NULL; } else if (rc) goto out_unlock; From bfbab2eaa3ff67a95273d94f16143eec6d1c763a Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Thu, 19 Jul 2018 20:16:39 +0530 Subject: [PATCH 123/392] msm: ipa: Setting appropriate config on MHI ep Couple of configuration updation on MHI ep, - During MHI suspend sequence, suspend DL channels first and followed by UL channels. Because, if MHI suspended during high tput scenario, there could be a chance that Q6 is still pumping data towards it. Due to which UL channels disconnection will fail and assert the device. - Set ep_delay on MHI CLIENT PROD ep upon connect, to prevent some random data getting into IPA before even Q6 configures it. - During SSR in pre-shutdown cleanup, set ep_delay and holb on MHI ep's to make sure there is no ipa stall due to some packet in/out. Since the ep configs are done by Q6 and which is down in SSR. Change-Id: Ie315892a2d1403a7e1f2ecf40c7b6c12d4e93c91 Signed-off-by: Mohammed Javid --- .../msm/ipa/ipa_clients/ipa_mhi_client.c | 20 +++--- drivers/platform/msm/ipa/ipa_v3/ipa.c | 10 ++- drivers/platform/msm/ipa/ipa_v3/ipa_client.c | 72 +++++++++++++++++-- drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 5 +- drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c | 33 +++++++++ 5 files changed, 122 insertions(+), 18 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c index 158be880b953..2143adbdac12 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c @@ -2119,6 +2119,15 @@ int ipa_mhi_suspend(bool force) IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res); return res; } + + res = ipa_mhi_suspend_dl(force); + if (res) { + IPA_MHI_ERR("ipa_mhi_suspend_dl failed %d\n", res); + goto fail_suspend_dl_channel; + } + + usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX); + res = ipa_mhi_suspend_ul(force, &empty, &force_clear); if (res) { IPA_MHI_ERR("ipa_mhi_suspend_ul failed %d\n", res); @@ -2147,12 +2156,6 @@ int ipa_mhi_suspend(bool force) usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX); - res = ipa_mhi_suspend_dl(force); - if (res) { - IPA_MHI_ERR("ipa_mhi_suspend_dl failed %d\n", res); - goto fail_suspend_dl_channel; - } - if (!empty) ipa_set_tag_process_before_gating(false); @@ -2166,14 +2169,12 @@ int ipa_mhi_suspend(bool force) IPA_MHI_FUNC_EXIT(); return 0; -fail_suspend_dl_channel: fail_release_cons: ipa_mhi_request_prod(); fail_release_prod: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); fail_suspend_ul_channel: ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->ul_channels); - ipa_mhi_set_state(IPA_MHI_STATE_STARTED); if (force_clear) { if ( ipa_mhi_disable_force_clear(ipa_mhi_client_ctx->qmi_req_id)) { @@ -2183,6 +2184,9 @@ int ipa_mhi_suspend(bool force) IPA_MHI_DBG("force clear datapath disabled\n"); ipa_mhi_client_ctx->qmi_req_id++; } +fail_suspend_dl_channel: + ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->dl_channels); + ipa_mhi_set_state(IPA_MHI_STATE_STARTED); return res; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 02db3e5bf87e..8ac4137a8446 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -2584,6 +2584,9 @@ void ipa3_q6_pre_shutdown_cleanup(void) ipa3_q6_pipe_delay(true); ipa3_q6_avoid_holb(); + if (ipa3_ctx->ipa_config_is_mhi) + ipa3_set_reset_client_cons_pipe_sus_holb(true, + IPA_CLIENT_MHI_CONS); if (ipa3_q6_clean_q6_tables()) { IPAERR("Failed to clean Q6 tables\n"); BUG(); @@ -2596,8 +2599,11 @@ void ipa3_q6_pre_shutdown_cleanup(void) * on pipe reset procedure */ ipa3_q6_pipe_delay(false); - - ipa3_set_usb_prod_pipe_delay(); + ipa3_set_reset_client_prod_pipe_delay(true, + IPA_CLIENT_USB_PROD); + if (ipa3_ctx->ipa_config_is_mhi) + ipa3_set_reset_client_prod_pipe_delay(true, + IPA_CLIENT_MHI_PROD); IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); IPADBG_LOW("Exit with success\n"); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 2478baff7ccd..9a6cda454435 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -1848,27 +1848,32 @@ static int ipa3_stop_ul_chan_with_data_drain(u32 qmi_req_id, } /* - * Set USB PROD pipe delay for MBIM/RMNET config + * Set reset eo_deay for CLEINT PROD pipe * Clocks, should be voted before calling this API * locks should be taken before calling this API */ -void ipa3_set_usb_prod_pipe_delay(void) +int ipa3_set_reset_client_prod_pipe_delay(bool set_reset, + enum ipa_client_type client) { - int result; + int result = 0; int pipe_idx; struct ipa3_ep_context *ep; struct ipa_ep_cfg_ctrl ep_ctrl; memset(&ep_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl)); - ep_ctrl.ipa_ep_delay = true; + ep_ctrl.ipa_ep_delay = set_reset; + if (IPA_CLIENT_IS_CONS(client)) { + IPAERR("client (%d) not PROD\n", client); + return -EINVAL; + } - pipe_idx = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD); + pipe_idx = ipa3_get_ep_mapping(client); if (pipe_idx == IPA_EP_NOT_ALLOCATED) { - IPAERR("client (%d) not valid\n", IPA_CLIENT_USB_PROD); - return; + IPAERR("client (%d) not valid\n", client); + return -EINVAL; } ep = &ipa3_ctx->ep[pipe_idx]; @@ -1885,6 +1890,59 @@ void ipa3_set_usb_prod_pipe_delay(void) IPADBG("client (ep: %d) success\n", pipe_idx); } client_lock_unlock_cb(pipe_idx, false); + return result; +} + +int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset, + enum ipa_client_type client) +{ + int pipe_idx; + struct ipa3_ep_context *ep; + struct ipa_ep_cfg_ctrl ep_suspend; + struct ipa_ep_cfg_holb ep_holb; + + memset(&ep_suspend, 0, sizeof(ep_suspend)); + memset(&ep_holb, 0, sizeof(ep_holb)); + + ep_suspend.ipa_ep_suspend = set_reset; + ep_holb.tmr_val = 0; + ep_holb.en = set_reset; + + if (IPA_CLIENT_IS_PROD(client)) { + IPAERR("client (%d) not CONS\n", client); + return -EINVAL; + } + + pipe_idx = ipa3_get_ep_mapping(client); + + if (pipe_idx == IPA_EP_NOT_ALLOCATED) { + IPAERR("client (%d) not valid\n", client); + return -EINVAL; + } + + ep = &ipa3_ctx->ep[pipe_idx]; + /* Setting sus/holb on MHI_CONS with skip_ep_cfg */ + client_lock_unlock_cb(pipe_idx, true); + if (ep->valid && ep->skip_ep_cfg) { + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_CTRL_n, + pipe_idx, &ep_suspend); + /* + * ipa3_cfg_ep_holb is not used here because we are + * setting HOLB on Q6 pipes, and from APPS perspective + * they are not valid, therefore, the above function + * will fail. + */ + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, + pipe_idx, &ep_holb); + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_HOL_BLOCK_EN_n, + pipe_idx, &ep_holb); + } + client_lock_unlock_cb(pipe_idx, false); + return 0; } void ipa3_xdci_ep_delay_rm(u32 clnt_hdl) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index b53a58cf9f70..61e8d8a3dea1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1530,7 +1530,10 @@ int ipa3_xdci_disconnect(u32 clnt_hdl, bool should_force_clear, u32 qmi_req_id); void ipa3_xdci_ep_delay_rm(u32 clnt_hdl); void ipa3_register_lock_unlock_callback(int (*client_cb)(bool), u32 ipa_ep_idx); void ipa3_deregister_lock_unlock_callback(u32 ipa_ep_idx); -void ipa3_set_usb_prod_pipe_delay(void); +int ipa3_set_reset_client_prod_pipe_delay(bool set_reset, + enum ipa_client_type client); +int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset, + enum ipa_client_type client); int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool should_force_clear, u32 qmi_req_id, bool is_dpl); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index c56a60f7a7fc..45340fcdd4d1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -198,6 +198,7 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, union __packed gsi_channel_scratch ch_scratch; struct ipa3_ep_context *ep; const struct ipa_gsi_ep_config *ep_cfg; + struct ipa_ep_cfg_ctrl ep_cfg_ctrl; IPA_MHI_FUNC_ENTRY(); @@ -323,6 +324,20 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, *params->mhi = ch_scratch.mhi; + if (IPA_CLIENT_IS_PROD(ep->client) && ep->skip_ep_cfg) { + memset(&ep_cfg_ctrl, 0 , sizeof(struct ipa_ep_cfg_ctrl)); + ep_cfg_ctrl.ipa_ep_delay = true; + ep->ep_delay_set = true; + res = ipa3_cfg_ep_ctrl(ipa_ep_idx, &ep_cfg_ctrl); + if (res) + IPA_MHI_ERR("client (ep: %d) failed result=%d\n", + ipa_ep_idx, res); + else + IPA_MHI_DBG("client (ep: %d) success\n", ipa_ep_idx); + } else { + ep->ep_delay_set = false; + } + IPA_MHI_DBG("Starting channel\n"); res = gsi_start_channel(ep->gsi_chan_hdl); if (res) { @@ -496,6 +511,7 @@ int ipa3_disconnect_mhi_pipe(u32 clnt_hdl) { struct ipa3_ep_context *ep; int res; + struct ipa_ep_cfg_ctrl ep_cfg_ctrl; IPA_MHI_FUNC_ENTRY(); @@ -510,6 +526,23 @@ int ipa3_disconnect_mhi_pipe(u32 clnt_hdl) } ep = &ipa3_ctx->ep[clnt_hdl]; + IPA_MHI_ERR("Debug --> Remove ep_delay start"); + if (ep->ep_delay_set == true) { + memset(&ep_cfg_ctrl, 0 , sizeof(struct ipa_ep_cfg_ctrl)); + ep_cfg_ctrl.ipa_ep_delay = false; + res = ipa3_cfg_ep_ctrl(clnt_hdl, + &ep_cfg_ctrl); + if (res) { + IPAERR + ("client(ep:%d) failed to remove delay res=%d\n", + clnt_hdl, res); + } else { + IPADBG("client (ep: %d) delay removed\n", + clnt_hdl); + ep->ep_delay_set = false; + } + } + IPA_MHI_ERR("Debug --> Remov ep_delay end"); if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) { res = gsi_dealloc_channel(ep->gsi_chan_hdl); From b42263f48e0c2673bc7e1e8f927168790dbdf825 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Fri, 25 May 2018 20:19:45 +0530 Subject: [PATCH 124/392] msm: mhi_dev: Switch to look-up table for UCI channel attributes Use a look-up table to easily add or remove support for UCI SW channels. The table includes the channel id, direction, TRB size, number of TRBs and a boolean flag indicating whether to register a channel state change notification with the MHI driver. Change-Id: I8697c24ee559546e279eac51cf9365d7570612e3 Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi_uci.c | 280 ++++++++++++++++--------- include/linux/msm_mhi_dev.h | 1 + 2 files changed, 187 insertions(+), 94 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 4d9aa2e5e83f..ddf17f3cae56 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -35,7 +35,7 @@ #define MHI_SOFTWARE_CLIENT_LIMIT (MHI_MAX_SOFTWARE_CHANNELS/2) #define MHI_UCI_IPC_LOG_PAGES (100) -#define MAX_NR_TRBS_PER_CHAN 1 +#define MAX_NR_TRBS_PER_CHAN 9 #define MHI_QTI_IFACE_ID 4 #define DEVICE_NAME "mhi" @@ -70,7 +70,131 @@ struct chan_attr { u32 nr_trbs; /* direction of the channel, see enum mhi_chan_dir */ enum mhi_chan_dir dir; - u32 uci_ownership; + /* need to register mhi channel state change callback */ + bool register_cb; +}; + +/* UCI channel attributes table */ +static const struct chan_attr uci_chan_attr_table[] = { + { + MHI_CLIENT_LOOPBACK_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_LOOPBACK_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_SAHARA_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_SAHARA_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_EFS_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_EFS_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_MBIM_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_MBIM_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_QMI_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_QMI_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_IP_CTRL_0_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_IP_CTRL_0_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_IP_CTRL_1_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_IP_CTRL_1_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { + MHI_CLIENT_DUN_OUT, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_OUT, + false + }, + { + MHI_CLIENT_DUN_IN, + TRB_MAX_DATA_SIZE, + MAX_NR_TRBS_PER_CHAN, + MHI_DIR_IN, + false + }, + { /* Must be the last */ + MHI_CLIENT_INVALID, + 0, + 0, + MHI_DIR_INVALID, + false + }, }; struct uci_ctrl { @@ -87,6 +211,8 @@ struct uci_client { u32 in_chan; struct mhi_dev_client *out_handle; struct mhi_dev_client *in_handle; + const struct chan_attr *in_chan_attr; + const struct chan_attr *out_chan_attr; wait_queue_head_t read_wq; wait_queue_head_t write_wq; atomic_t read_data_ready; @@ -104,7 +230,6 @@ struct uci_client { }; struct mhi_uci_ctxt_t { - struct chan_attr chan_attrib[MHI_MAX_SOFTWARE_CHANNELS]; struct uci_client client_handles[MHI_SOFTWARE_CLIENT_LIMIT]; struct uci_ctrl ctrl_handle; void (*event_notifier)(struct mhi_dev_client_cb_reason *cb); @@ -119,6 +244,7 @@ struct mhi_uci_ctxt_t { }; #define CHAN_TO_CLIENT(_CHAN_NR) (_CHAN_NR / 2) +#define CLIENT_TO_CHAN(_CLIENT_NR) (_CLIENT_NR * 2) #define uci_log(_msg_lvl, _msg, ...) do { \ if (_msg_lvl >= mhi_uci_msg_lvl) { \ @@ -155,8 +281,8 @@ static int mhi_init_read_chan(struct uci_client *client_handle, enum mhi_client_channel chan) { int rc = 0; - u32 i , j; - struct chan_attr *chan_attributes; + u32 i, j; + const struct chan_attr *in_chan_attr; size_t buf_size; void *data_loc; @@ -169,10 +295,15 @@ static int mhi_init_read_chan(struct uci_client *client_handle, return -EINVAL; } - chan_attributes = &uci_ctxt.chan_attrib[chan]; - buf_size = chan_attributes->max_packet_size; + in_chan_attr = client_handle->in_chan_attr; + if (!in_chan_attr) { + uci_log(UCI_DBG_ERROR, "Null channel attributes for chan %d\n", + client_handle->in_chan); + return -EINVAL; + } + buf_size = in_chan_attr->max_packet_size; - for (i = 0; i < (chan_attributes->nr_trbs); i++) { + for (i = 0; i < (in_chan_attr->nr_trbs); i++) { data_loc = kmalloc(buf_size, GFP_KERNEL); if (!data_loc) { rc = -ENOMEM; @@ -397,20 +528,11 @@ static int mhi_uci_client_release(struct inode *mhi_inode, struct file *file_handle) { struct uci_client *uci_handle = file_handle->private_data; - struct mhi_uci_ctxt_t *uci_ctxt; - u32 nr_in_bufs = 0; int rc = 0; - int in_chan = 0; - u32 buf_size = 0; if (!uci_handle) return -EINVAL; - uci_ctxt = uci_handle->uci_ctxt; - in_chan = iminor(mhi_inode) + 1; - nr_in_bufs = uci_ctxt->chan_attrib[in_chan].nr_trbs; - buf_size = uci_ctxt->chan_attrib[in_chan].max_packet_size; - if (atomic_sub_return(1, &uci_handle->ref_count) == 0) { uci_log(UCI_DBG_DBG, "Last client left, closing channel 0x%x\n", @@ -750,54 +872,25 @@ static ssize_t mhi_uci_client_write(struct file *file, static int uci_init_client_attributes(struct mhi_uci_ctxt_t *uci_ctxt) { - u32 i = 0; - u32 data_size = TRB_MAX_DATA_SIZE; - u32 index = 0; + u32 i; + u32 index; struct uci_client *client; - struct chan_attr *chan_attrib = NULL; - - for (i = 0; i < ARRAY_SIZE(uci_ctxt->chan_attrib); i++) { - chan_attrib = &uci_ctxt->chan_attrib[i]; - switch (i) { - case MHI_CLIENT_LOOPBACK_OUT: - case MHI_CLIENT_LOOPBACK_IN: - case MHI_CLIENT_SAHARA_OUT: - case MHI_CLIENT_SAHARA_IN: - case MHI_CLIENT_EFS_OUT: - case MHI_CLIENT_EFS_IN: - case MHI_CLIENT_MBIM_OUT: - case MHI_CLIENT_MBIM_IN: - case MHI_CLIENT_QMI_OUT: - case MHI_CLIENT_QMI_IN: - case MHI_CLIENT_IP_CTRL_0_OUT: - case MHI_CLIENT_IP_CTRL_0_IN: - case MHI_CLIENT_IP_CTRL_1_OUT: - case MHI_CLIENT_IP_CTRL_1_IN: - case MHI_CLIENT_DUN_OUT: - case MHI_CLIENT_DUN_IN: - chan_attrib->uci_ownership = 1; - break; - default: - chan_attrib->uci_ownership = 0; + const struct chan_attr *chan_attrib; + + for (i = 0; i < ARRAY_SIZE(uci_chan_attr_table); i += 2) { + chan_attrib = &uci_chan_attr_table[i]; + if (chan_attrib->chan_id == MHI_CLIENT_INVALID) break; - } - if (chan_attrib->uci_ownership) { - chan_attrib->chan_id = i; - chan_attrib->max_packet_size = data_size; - index = CHAN_TO_CLIENT(i); - client = &uci_ctxt->client_handles[index]; - chan_attrib->nr_trbs = 9; - client->in_buf_list = - kmalloc(sizeof(struct mhi_dev_iov) * - chan_attrib->nr_trbs, + index = CHAN_TO_CLIENT(i); + client = &uci_ctxt->client_handles[index]; + client->out_chan_attr = chan_attrib; + client->in_chan_attr = ++chan_attrib; + client->in_buf_list = + kcalloc(chan_attrib->nr_trbs, + sizeof(struct mhi_dev_iov), GFP_KERNEL); - if (NULL == client->in_buf_list) - return -ENOMEM; - } - if (i % 2 == 0) - chan_attrib->dir = MHI_DIR_OUT; - else - chan_attrib->dir = MHI_DIR_IN; + if (!client->in_buf_list) + return -ENOMEM; } return 0; } @@ -949,16 +1042,14 @@ int mhi_uci_init(void) uci_log(UCI_DBG_INFO, "Registering for MHI events.\n"); for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; i++) { - if (uci_ctxt.chan_attrib[i * 2].uci_ownership) { - mhi_client = &uci_ctxt.client_handles[i]; - - r = mhi_register_client(mhi_client, i); - - if (r) { - uci_log(UCI_DBG_CRITICAL, - "Failed to reg client %d ret %d\n", - r, i); - } + mhi_client = &uci_ctxt.client_handles[i]; + if (!mhi_client->in_chan_attr) + continue; + r = mhi_register_client(mhi_client, i); + if (r) { + uci_log(UCI_DBG_CRITICAL, + "Failed to reg client %d ret %d\n", + r, i); } } @@ -992,29 +1083,30 @@ int mhi_uci_init(void) uci_log(UCI_DBG_INFO, "Setting up device nodes.\n"); for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; i++) { - if (uci_ctxt.chan_attrib[i*2].uci_ownership) { - cdev_init(&uci_ctxt.cdev[i], &mhi_uci_client_fops); - uci_ctxt.cdev[i].owner = THIS_MODULE; - r = cdev_add(&uci_ctxt.cdev[i], - uci_ctxt.start_ctrl_nr + i , 1); - if (IS_ERR_VALUE(r)) { - uci_log(UCI_DBG_ERROR, - "Failed to add cdev %d, ret 0x%x\n", - i, r); - goto failed_char_add; - } + mhi_client = &uci_ctxt.client_handles[i]; + if (!mhi_client->in_chan_attr) + continue; + cdev_init(&uci_ctxt.cdev[i], &mhi_uci_client_fops); + uci_ctxt.cdev[i].owner = THIS_MODULE; + r = cdev_add(&uci_ctxt.cdev[i], + uci_ctxt.start_ctrl_nr + i, 1); + if (IS_ERR_VALUE(r)) { + uci_log(UCI_DBG_ERROR, + "Failed to add cdev %d, ret 0x%x\n", + i, r); + goto failed_char_add; + } - uci_ctxt.client_handles[i].dev = - device_create(uci_ctxt.mhi_uci_class, NULL, - uci_ctxt.start_ctrl_nr + i, - NULL, DEVICE_NAME "_pipe_%d", - i * 2); - if (IS_ERR(uci_ctxt.client_handles[i].dev)) { - uci_log(UCI_DBG_ERROR, - "Failed to add cdev %d\n", i); - cdev_del(&uci_ctxt.cdev[i]); - goto failed_device_create; - } + uci_ctxt.client_handles[i].dev = + device_create(uci_ctxt.mhi_uci_class, NULL, + uci_ctxt.start_ctrl_nr + i, + NULL, DEVICE_NAME "_pipe_%d", + i * 2); + if (IS_ERR(uci_ctxt.client_handles[i].dev)) { + uci_log(UCI_DBG_ERROR, + "Failed to add cdev %d\n", i); + cdev_del(&uci_ctxt.cdev[i]); + goto failed_device_create; } } diff --git a/include/linux/msm_mhi_dev.h b/include/linux/msm_mhi_dev.h index 7eb1d06f956d..e7656972c13c 100644 --- a/include/linux/msm_mhi_dev.h +++ b/include/linux/msm_mhi_dev.h @@ -135,6 +135,7 @@ enum mhi_client_channel { MHI_CLIENT_RESERVED_2_LOWER = 102, MHI_CLIENT_RESERVED_2_UPPER = 127, MHI_MAX_CHANNELS = 102, + MHI_CLIENT_INVALID = 0xFFFFFFFF }; struct mhi_dev_client_cb_data { From 27fe6e2557ff57a7d3e805715de1f3dd97220164 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Fri, 1 Jun 2018 20:22:30 +0530 Subject: [PATCH 125/392] msm: mhi_dev: Add asynchronous read/write support in UCI driver Add and enable (by default) support for asynchronous reads and writes in the UCI driver. Clients can force the earlier synchronous reads and writes by specifying the O_SYNC file flag in the file open call. Change-Id: I4d283c2d56e169bf7dbf01cb57b75b1911ef401d Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi.c | 80 +++--- drivers/platform/msm/mhi_dev/mhi.h | 8 +- drivers/platform/msm/mhi_dev/mhi_uci.c | 339 ++++++++++++++++++++----- 3 files changed, 322 insertions(+), 105 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 056c999bcfbf..60ba17e6a208 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -1880,6 +1880,7 @@ int mhi_dev_open_channel(uint32_t chan_id, (struct mhi_dev_client_cb_reason *cb)) { int rc = 0; + int i = 0; struct mhi_dev_channel *ch; struct platform_device *pdev; @@ -1903,6 +1904,38 @@ int mhi_dev_open_channel(uint32_t chan_id, goto exit; } + /* Pre allocate event requests */ + ch->ereqs = kcalloc(MHI_MAX_EVT_REQ, sizeof(*ch->ereqs), GFP_KERNEL); + if (!ch->ereqs) { + rc = -ENOMEM; + goto free_client; + } + /* pre allocate buffers to queue transfer completion events */ + ch->tr_events = kcalloc(MHI_MAX_EVT_REQ, + MAX_TR_EVENTS * sizeof(*ch->tr_events), + GFP_KERNEL); + if (!ch->tr_events) { + rc = -ENOMEM; + goto free_ereqs; + } + + /* + * Organize the above allocated event request block and + * completion event block into linked lists. Each event + * request includes a pointer to a block of MAX_TR_EVENTS + * completion events. + */ + INIT_LIST_HEAD(&mhi_ctx->ch[chan_id].event_req_buffers); + for (i = 0; i < MHI_MAX_EVT_REQ; ++i) { + ch->ereqs[i].tr_events = ch->tr_events + i * MAX_TR_EVENTS; + list_add_tail(&ch->ereqs[i].list, + &mhi_ctx->ch[chan_id].event_req_buffers); + } + mhi_ctx->ch[chan_id].curr_ereq = + container_of(mhi_ctx->ch[chan_id].event_req_buffers.next, + struct event_req, list); + list_del_init(&mhi_ctx->ch[chan_id].curr_ereq->list); + ch->active_client = (*handle_client); (*handle_client)->channel = ch; (*handle_client)->event_trigger = mhi_dev_client_cb_reason; @@ -1915,6 +1948,13 @@ int mhi_dev_open_channel(uint32_t chan_id, else if (ch->state == MHI_DEV_CH_STOPPED) ch->state = MHI_DEV_CH_PENDING_START; + goto exit; + +free_ereqs: + kfree(ch->ereqs); + ch->ereqs = NULL; +free_client: + kfree(*handle_client); exit: mutex_unlock(&ch->ch_lock); return rc; @@ -1948,14 +1988,12 @@ int mhi_dev_close_channel(struct mhi_dev_client *handle) mhi_log(MHI_MSG_ERROR, "Trying to close an active channel (%d)\n", ch->ch_id); - mutex_unlock(&ch->ch_lock); rc = -EAGAIN; goto exit; } else if (ch->tre_loc) { mhi_log(MHI_MSG_ERROR, "Trying to close channel (%d) when a TRE is active", ch->ch_id); - mutex_unlock(&ch->ch_lock); rc = -EAGAIN; goto exit; } @@ -1963,6 +2001,10 @@ int mhi_dev_close_channel(struct mhi_dev_client *handle) ch->state = MHI_DEV_CH_CLOSED; ch->active_client = NULL; + kfree(ch->ereqs); + kfree(ch->tr_events); + ch->ereqs = NULL; + ch->tr_events = NULL; kfree(handle); exit: mutex_unlock(&ch->ch_lock); @@ -2670,40 +2712,8 @@ static int mhi_init(struct mhi_dev *mhi) if (!mhi->ch) return -ENOMEM; - - for (i = 0; i < mhi->cfg.channels; i++) { + for (i = 0; i < mhi->cfg.channels; i++) mutex_init(&mhi->ch[i].ch_lock); - if (i == MHI_CLIENT_IP_SW_4_OUT || i == MHI_CLIENT_IP_SW_4_IN) { - int nreq = 0; - - INIT_LIST_HEAD(&mhi->ch[i].event_req_buffers); - while (nreq < MHI_MAX_EVT_REQ) { - struct event_req *ereq; - /* Pre allocate event requests */ - ereq = kzalloc(sizeof(struct event_req), - GFP_KERNEL); - if (!ereq) - return -ENOMEM; - - /* pre allocate buffers to queue - * transfer completion events - */ - ereq->tr_events = kzalloc(RING_ELEMENT_TYPE_SZ* - MAX_TR_EVENTS, GFP_KERNEL); - if (!ereq->tr_events) { - kfree(ereq); - return -ENOMEM; - } - list_add_tail(&ereq->list, - &mhi->ch[i].event_req_buffers); - nreq++; - } - mhi->ch[i].curr_ereq = - container_of(mhi->ch[i].event_req_buffers.next, - struct event_req, list); - list_del_init(&mhi->ch[i].curr_ereq->list); - } - } spin_lock_init(&mhi->lock); mhi->mmio_backup = devm_kzalloc(&pdev->dev, diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index d764e1c0eb67..147a435897a9 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -440,7 +440,13 @@ struct mhi_dev_channel { struct mutex ch_lock; /* client which the current inbound/outbound message is for */ struct mhi_dev_client *active_client; - + /* + * Pointer to event request structs used to temporarily store + * completion events and meta data before sending them to host + */ + struct event_req *ereqs; + /* Pointer to completion event buffers */ + union mhi_dev_ring_element_type *tr_events; struct list_head event_req_buffers; struct event_req *curr_ereq; diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index ddf17f3cae56..3282dff6a7c7 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -35,9 +35,13 @@ #define MHI_SOFTWARE_CLIENT_LIMIT (MHI_MAX_SOFTWARE_CHANNELS/2) #define MHI_UCI_IPC_LOG_PAGES (100) +/* Max number of MHI write request structures (used in async writes) */ +#define MAX_UCI_WR_REQ 10 #define MAX_NR_TRBS_PER_CHAN 9 #define MHI_QTI_IFACE_ID 4 -#define DEVICE_NAME "mhi" +#define DEVICE_NAME "mhi" + +#define MHI_UCI_ASYNC_READ_TIMEOUT msecs_to_jiffies(100) enum uci_dbg_level { UCI_DBG_VERBOSE = 0x0, @@ -227,6 +231,13 @@ struct uci_client { struct mhi_uci_ctxt_t *uci_ctxt; struct mutex in_chan_lock; struct mutex out_chan_lock; + spinlock_t wr_req_lock; + unsigned int f_flags; + struct mhi_req *wreqs; + struct list_head wr_req_list; + struct completion read_done; + int (*send)(struct uci_client*, void*, u32); + int (*read)(struct uci_client*, struct mhi_req*, int*); }; struct mhi_uci_ctxt_t { @@ -301,8 +312,11 @@ static int mhi_init_read_chan(struct uci_client *client_handle, client_handle->in_chan); return -EINVAL; } - buf_size = in_chan_attr->max_packet_size; + /* Init the completion event for read */ + init_completion(&client_handle->read_done); + + buf_size = in_chan_attr->max_packet_size; for (i = 0; i < (in_chan_attr->nr_trbs); i++) { data_loc = kmalloc(buf_size, GFP_KERNEL); if (!data_loc) { @@ -322,48 +336,129 @@ static int mhi_init_read_chan(struct uci_client *client_handle, return rc; } -static int mhi_uci_send_packet(struct mhi_dev_client **client_handle, void *buf, - u32 size, u32 is_uspace_buf) +static void mhi_uci_write_completion_cb(void *req) { - void *data_loc = NULL; - uintptr_t memcpy_result = 0; - u32 data_inserted_so_far = 0; + struct mhi_req *ureq = req; struct uci_client *uci_handle; - struct mhi_req ureq; + unsigned long flags; + uci_handle = (struct uci_client *)ureq->context; + kfree(ureq->buf); + ureq->buf = NULL; - uci_handle = container_of(client_handle, struct uci_client, - out_handle); + spin_lock_irqsave(&uci_handle->wr_req_lock, flags); + list_add_tail(&ureq->list, &uci_handle->wr_req_list); + spin_unlock_irqrestore(&uci_handle->wr_req_lock, flags); +} - if (!client_handle || !buf || - !size || !uci_handle) - return -EINVAL; +static void mhi_uci_read_completion_cb(void *req) +{ + struct mhi_req *ureq = req; + struct uci_client *uci_handle; - if (is_uspace_buf) { - data_loc = kmalloc(size, GFP_KERNEL); - if (!data_loc) { - uci_log(UCI_DBG_ERROR, - "Failed to allocate memory 0x%x\n", - size); - return -ENOMEM; - } - memcpy_result = copy_from_user(data_loc, buf, size); - if (memcpy_result) - goto error_memcpy; - } else { - data_loc = buf; - } - ureq.client = *client_handle; + uci_handle = (struct uci_client *)ureq->context; + complete(&uci_handle->read_done); +} + +static int mhi_uci_send_sync(struct uci_client *uci_handle, + void *data_loc, u32 size) +{ + struct mhi_req ureq; + int ret_val; + + ureq.client = uci_handle->out_handle; ureq.buf = data_loc; ureq.len = size; ureq.chan = uci_handle->out_chan; ureq.mode = IPA_DMA_SYNC; - data_inserted_so_far = mhi_dev_write_channel(&ureq); + ret_val = mhi_dev_write_channel(&ureq); + + kfree(data_loc); + return ret_val; +} + +static int mhi_uci_send_async(struct uci_client *uci_handle, + void *data_loc, u32 size) +{ + int bytes_to_write; + struct mhi_req *ureq; + + uci_log(UCI_DBG_VERBOSE, + "Got async write for ch %d of size %d\n", + uci_handle->out_chan, size); + + spin_lock_irq(&uci_handle->wr_req_lock); + if (list_empty(&uci_handle->wr_req_list)) { + uci_log(UCI_DBG_ERROR, "Write request pool empty\n"); + spin_unlock_irq(&uci_handle->wr_req_lock); + return -ENOMEM; + } + ureq = container_of(uci_handle->wr_req_list.next, + struct mhi_req, list); + list_del_init(&ureq->list); + spin_unlock_irq(&uci_handle->wr_req_lock); + + ureq->client = uci_handle->out_handle; + ureq->context = uci_handle; + ureq->buf = data_loc; + ureq->len = size; + ureq->chan = uci_handle->out_chan; + ureq->mode = IPA_DMA_ASYNC; + ureq->client_cb = mhi_uci_write_completion_cb; + ureq->snd_cmpl = 1; + + bytes_to_write = mhi_dev_write_channel(ureq); + if (bytes_to_write != size) + goto error_async_transfer; + + return bytes_to_write; + +error_async_transfer: + kfree(data_loc); + ureq->buf = NULL; + spin_lock_irq(&uci_handle->wr_req_lock); + list_add_tail(&ureq->list, &uci_handle->wr_req_list); + spin_unlock_irq(&uci_handle->wr_req_lock); + + return bytes_to_write; +} + +static int mhi_uci_send_packet(struct mhi_dev_client **client_handle, + const char __user *buf, u32 size) +{ + void *data_loc; + unsigned long memcpy_result; + struct uci_client *uci_handle; + + if (!client_handle || !buf || !size) + return -EINVAL; + + if (size > TRB_MAX_DATA_SIZE) { + uci_log(UCI_DBG_ERROR, + "Too big write size: %d, max supported size is %d\n", + size, TRB_MAX_DATA_SIZE); + return -EFBIG; + } + + uci_handle = container_of(client_handle, struct uci_client, + out_handle); + data_loc = kmalloc(size, GFP_KERNEL); + if (!data_loc) { + uci_log(UCI_DBG_ERROR, + "Failed to allocate kernel buf for user requested size 0x%x\n", + size); + return -ENOMEM; + } + memcpy_result = copy_from_user(data_loc, buf, size); + if (memcpy_result) + goto error_memcpy; + + return uci_handle->send(uci_handle, data_loc, size); error_memcpy: kfree(data_loc); - return data_inserted_so_far; + return -EFAULT; } static unsigned int mhi_uci_ctrl_poll(struct file *file, poll_table *wait) @@ -421,6 +516,119 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait) return mask; } +static int mhi_uci_alloc_write_reqs(struct uci_client *client) +{ + int i; + + client->wreqs = kcalloc(MAX_UCI_WR_REQ, + sizeof(struct mhi_req), + GFP_KERNEL); + if (!client->wreqs) { + uci_log(UCI_DBG_ERROR, "Write reqs alloc failed\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&client->wr_req_list); + for (i = 0; i < MAX_UCI_WR_REQ; ++i) + list_add_tail(&client->wreqs[i].list, &client->wr_req_list); + + uci_log(UCI_DBG_INFO, + "UCI write reqs allocation successful\n"); + return 0; +} + +static int mhi_uci_read_async(struct uci_client *uci_handle, + struct mhi_req *ureq, int *bytes_avail) +{ + int ret_val = 0; + unsigned long compl_ret; + + uci_log(UCI_DBG_ERROR, + "Async read for ch %d\n", uci_handle->in_chan); + + ureq->mode = IPA_DMA_ASYNC; + ureq->client_cb = mhi_uci_read_completion_cb; + ureq->snd_cmpl = 1; + ureq->context = uci_handle; + + reinit_completion(&uci_handle->read_done); + + *bytes_avail = mhi_dev_read_channel(ureq); + uci_log(UCI_DBG_VERBOSE, "buf_size = 0x%x bytes_read = 0x%x\n", + ureq->len, *bytes_avail); + if (*bytes_avail < 0) { + uci_log(UCI_DBG_ERROR, "Failed to read channel ret %d\n", + *bytes_avail); + return -EIO; + } + + if (*bytes_avail > 0) { + uci_log(UCI_DBG_VERBOSE, + "Waiting for async read completion!\n"); + compl_ret = + wait_for_completion_interruptible_timeout( + &uci_handle->read_done, + MHI_UCI_ASYNC_READ_TIMEOUT); + + if (compl_ret == -ERESTARTSYS) { + uci_log(UCI_DBG_ERROR, "Exit signal caught\n"); + return compl_ret; + } else if (compl_ret == 0) { + uci_log(UCI_DBG_ERROR, "Read timed out for ch %d\n", + uci_handle->in_chan); + return -EIO; + } + uci_log(UCI_DBG_VERBOSE, + "wk up Read completed on ch %d\n", ureq->chan); + + uci_handle->pkt_loc = (void *)ureq->buf; + uci_handle->pkt_size = ureq->actual_len; + + uci_log(UCI_DBG_VERBOSE, + "Got pkt of sz 0x%x at adr %pK, ch %d\n", + uci_handle->pkt_size, + ureq->buf, ureq->chan); + } else { + uci_handle->pkt_loc = NULL; + uci_handle->pkt_size = 0; + } + + return ret_val; +} + +static int mhi_uci_read_sync(struct uci_client *uci_handle, + struct mhi_req *ureq, int *bytes_avail) +{ + int ret_val = 0; + + ureq->mode = IPA_DMA_SYNC; + *bytes_avail = mhi_dev_read_channel(ureq); + + uci_log(UCI_DBG_VERBOSE, "buf_size = 0x%x bytes_read = 0x%x\n", + ureq->len, *bytes_avail); + + if (*bytes_avail < 0) { + uci_log(UCI_DBG_ERROR, "Failed to read channel ret %d\n", + *bytes_avail); + return -EIO; + } + + if (*bytes_avail > 0) { + uci_handle->pkt_loc = (void *)ureq->buf; + uci_handle->pkt_size = ureq->actual_len; + + uci_log(UCI_DBG_VERBOSE, + "Got pkt of sz 0x%x at adr %pK, ch %d\n", + uci_handle->pkt_size, + ureq->buf, ureq->chan); + } else { + uci_handle->pkt_loc = NULL; + uci_handle->pkt_size = 0; + } + + return ret_val; +} + static int open_client_mhi_channels(struct uci_client *uci_client) { int rc = 0; @@ -431,16 +639,27 @@ static int open_client_mhi_channels(struct uci_client *uci_client) uci_client->in_chan); mutex_lock(&uci_client->out_chan_lock); mutex_lock(&uci_client->in_chan_lock); + + /* Allocate write requests for async operations */ + if (!(uci_client->f_flags & O_SYNC)) { + rc = mhi_uci_alloc_write_reqs(uci_client); + if (rc) + goto handle_not_rdy_err; + uci_client->send = mhi_uci_send_async; + uci_client->read = mhi_uci_read_async; + } else { + uci_client->send = mhi_uci_send_sync; + uci_client->read = mhi_uci_read_sync; + } + uci_log(UCI_DBG_DBG, "Initializing inbound chan %d.\n", uci_client->in_chan); - rc = mhi_init_read_chan(uci_client, uci_client->in_chan); - if (rc < 0) { + if (rc < 0) uci_log(UCI_DBG_ERROR, "Failed to init inbound 0x%x, ret 0x%x\n", uci_client->in_chan, rc); - } rc = mhi_dev_open_channel(uci_client->out_chan, &uci_client->out_handle, @@ -451,7 +670,6 @@ static int open_client_mhi_channels(struct uci_client *uci_client) rc = mhi_dev_open_channel(uci_client->in_chan, &uci_client->in_handle, uci_ctxt.event_notifier); - if (rc < 0) { uci_log(UCI_DBG_ERROR, "Failed to open chan %d, ret 0x%x\n", @@ -506,6 +724,7 @@ static int mhi_uci_client_open(struct inode *mhi_inode, return -ENOMEM; } uci_handle->uci_ctxt = &uci_ctxt; + uci_handle->f_flags = file_handle->f_flags; if (!atomic_read(&uci_handle->mhi_chans_open)) { uci_log(UCI_DBG_INFO, "Opening channels client %d\n", @@ -540,6 +759,8 @@ static int mhi_uci_client_release(struct inode *mhi_inode, if (atomic_read(&uci_handle->mhi_chans_open)) { atomic_set(&uci_handle->mhi_chans_open, 0); + if (!(uci_handle->f_flags & O_SYNC)) + kfree(uci_handle->wreqs); mutex_lock(&uci_handle->out_chan_lock); rc = mhi_dev_close_channel(uci_handle->out_handle); wake_up(&uci_handle->write_wq); @@ -675,7 +896,6 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *ubuf, struct mutex *mutex; ssize_t bytes_copied = 0; u32 addr_offset = 0; - void *local_buf = NULL; struct mhi_req ureq; if (!file || !ubuf || !uspace_buf_size || @@ -691,44 +911,19 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *ubuf, ureq.client = client_handle; ureq.buf = uci_handle->in_buf_list[0].addr; ureq.len = uci_handle->in_buf_list[0].buf_size; - ureq.mode = IPA_DMA_SYNC; + uci_log(UCI_DBG_VERBOSE, "Client attempted read on chan %d\n", ureq.chan); do { if (!uci_handle->pkt_loc && - !atomic_read(&uci_ctxt.mhi_disabled)) { - - bytes_avail = mhi_dev_read_channel(&ureq); - - uci_log(UCI_DBG_VERBOSE, - "reading from mhi_core local_buf = %p", - local_buf); - uci_log(UCI_DBG_VERBOSE, - "buf_size = 0x%x bytes_read = 0x%x\n", - ureq.len, bytes_avail); - - if (bytes_avail < 0) { - uci_log(UCI_DBG_ERROR, - "Failed to read channel ret %d\n", - bytes_avail); - ret_val = -EIO; + !atomic_read(&uci_ctxt.mhi_disabled)) { + ret_val = uci_handle->read(uci_handle, &ureq, + &bytes_avail); + if (ret_val) goto error; - } - - if (bytes_avail > 0) { - uci_handle->pkt_loc = (void *) ureq.buf; - uci_handle->pkt_size = ureq.actual_len; - + if (bytes_avail > 0) *bytes_pending = (loff_t)uci_handle->pkt_size; - uci_log(UCI_DBG_VERBOSE, - "Got pkt of sz 0x%x at adr %p, ch %d\n", - uci_handle->pkt_size, - ureq.buf, ureq.chan); - } else { - uci_handle->pkt_loc = 0; - uci_handle->pkt_size = 0; - } } if (bytes_avail == 0) { @@ -737,7 +932,10 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *ubuf, "No data read_data_ready %d, chan %d\n", atomic_read(&uci_handle->read_data_ready), ureq.chan); - + if (uci_handle->f_flags & (O_NONBLOCK | O_NDELAY)) { + ret_val = -EAGAIN; + goto error; + } ret_val = wait_event_interruptible(uci_handle->read_wq, (!mhi_dev_channel_isempty(client_handle))); @@ -841,10 +1039,10 @@ static ssize_t mhi_uci_client_write(struct file *file, mutex_lock(&uci_handle->out_chan_lock); while (!ret_val) { ret_val = mhi_uci_send_packet(&uci_handle->out_handle, - (void *)buf, count, 1); + buf, count); if (ret_val < 0) { uci_log(UCI_DBG_ERROR, - "Error while writing data to MHI, chan %d, buf %p, size %d\n", + "Error while writing data to MHI, chan %d, buf %pK, size %d\n", chan, (void *)buf, count); ret_val = -EIO; break; @@ -854,6 +1052,8 @@ static ssize_t mhi_uci_client_write(struct file *file, "No descriptors available, did we poll, chan %d?\n", chan); mutex_unlock(&uci_handle->out_chan_lock); + if (uci_handle->f_flags & (O_NONBLOCK | O_NDELAY)) + return -EAGAIN; ret_val = wait_event_interruptible(uci_handle->write_wq, !mhi_dev_channel_isempty( uci_handle->out_handle)); @@ -945,6 +1145,7 @@ static int mhi_register_client(struct uci_client *mhi_client, int index) mutex_init(&mhi_client->in_chan_lock); mutex_init(&mhi_client->out_chan_lock); + spin_lock_init(&mhi_client->wr_req_lock); uci_log(UCI_DBG_DBG, "Registering chan %d.\n", mhi_client->out_chan); return 0; From 153005467726432c707b8faf1989eedc5a1cd586 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Fri, 29 Jun 2018 15:13:52 +0530 Subject: [PATCH 126/392] msm: mhi_dev: Initialize UCI client channel numbers early Move the channel number initialization for UCI clients to uci_init_client_attributes function to ensure the correct channel number is used for registering callback with the MHI driver. Correct the index used to retrieve the client handle. Change-Id: I5987366aed582ac47895a1310e0e0ee0de07c470 Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi_uci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 3282dff6a7c7..41360fbbafd6 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -1081,10 +1081,12 @@ static int uci_init_client_attributes(struct mhi_uci_ctxt_t *uci_ctxt) chan_attrib = &uci_chan_attr_table[i]; if (chan_attrib->chan_id == MHI_CLIENT_INVALID) break; - index = CHAN_TO_CLIENT(i); + index = CHAN_TO_CLIENT(chan_attrib->chan_id); client = &uci_ctxt->client_handles[index]; client->out_chan_attr = chan_attrib; client->in_chan_attr = ++chan_attrib; + client->in_chan = index * 2; + client->out_chan = index * 2 + 1; client->in_buf_list = kcalloc(chan_attrib->nr_trbs, sizeof(struct mhi_dev_iov), @@ -1139,8 +1141,6 @@ static int mhi_register_client(struct uci_client *mhi_client, int index) { init_waitqueue_head(&mhi_client->read_wq); init_waitqueue_head(&mhi_client->write_wq); - mhi_client->out_chan = index * 2 + 1; - mhi_client->in_chan = index * 2; mhi_client->client_index = index; mutex_init(&mhi_client->in_chan_lock); From 0fe8597e9b498f3ec9e7afa6c8b340f136bfb328 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Mon, 30 Jul 2018 20:01:04 +0530 Subject: [PATCH 127/392] msm: mhi_dev: Handle wrap-around case for event ring updates Asynchronous reads/writes may result in multiple elements being added to the event ring in a single update. This change accounts for the wrap-around case when updating a ring with multiple elements. Change-Id: I4fca542da488ae812dbb57f2d651a472092b39eb Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi_ring.c | 71 ++++++++++++++++++------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_ring.c b/drivers/platform/msm/mhi_dev/mhi_ring.c index 785d6d00568d..91496a46f5c8 100644 --- a/drivers/platform/msm/mhi_dev/mhi_ring.c +++ b/drivers/platform/msm/mhi_dev/mhi_ring.c @@ -264,11 +264,12 @@ EXPORT_SYMBOL(mhi_dev_process_ring); int mhi_dev_add_element(struct mhi_dev_ring *ring, union mhi_dev_ring_element_type *element, - struct event_req *ereq, int evt_offset) + struct event_req *ereq, int size) { uint32_t old_offset = 0; struct mhi_addr host_addr; - uint32_t num_elem = 0; + uint32_t num_elem = 1; + uint32_t num_free_elem; if (!ring || !element) { pr_err("%s: Invalid context\n", __func__); @@ -277,16 +278,24 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring, mhi_dev_update_wr_offset(ring); - if ((ring->rd_offset + 1) % ring->ring_size == ring->wr_offset) { - mhi_log(MHI_MSG_VERBOSE, "ring full to insert element\n"); + if (ereq) + num_elem = size / (sizeof(union mhi_dev_ring_element_type)); + + if (ring->rd_offset < ring->wr_offset) + num_free_elem = ring->wr_offset - ring->rd_offset - 1; + else + num_free_elem = ring->ring_size - ring->rd_offset + + ring->wr_offset - 1; + + if (num_free_elem < num_elem) { + mhi_log(MHI_MSG_ERROR, "No space to add %d elem in ring (%d)\n", + num_elem, ring->id); return -EINVAL; } old_offset = ring->rd_offset; - if (evt_offset) { - num_elem = evt_offset / - (sizeof(union mhi_dev_ring_element_type)); + if (ereq) { ring->rd_offset += num_elem; if (ring->rd_offset >= ring->ring_size) ring->rd_offset -= ring->ring_size; @@ -308,23 +317,47 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring, host_addr.device_va = ring->ring_shadow.device_va + sizeof(union mhi_dev_ring_element_type) * old_offset; - host_addr.virt_addr = element; - - if (evt_offset) - host_addr.size = evt_offset; - else + if (!ereq) { + /* We're adding only a single ring element */ + host_addr.virt_addr = element; host_addr.size = sizeof(union mhi_dev_ring_element_type); - mhi_log(MHI_MSG_VERBOSE, "adding element to ring (%d)\n", ring->id); - mhi_log(MHI_MSG_VERBOSE, "rd_ofset %d\n", ring->rd_offset); - mhi_log(MHI_MSG_VERBOSE, "type %d\n", element->generic.type); + mhi_log(MHI_MSG_VERBOSE, "adding element to ring (%d)\n", + ring->id); + mhi_log(MHI_MSG_VERBOSE, "rd_ofset %d\n", ring->rd_offset); + mhi_log(MHI_MSG_VERBOSE, "type %d\n", element->generic.type); - if (ereq) mhi_dev_write_to_host(ring->mhi_dev, &host_addr, - ereq, MHI_DEV_DMA_ASYNC); - else + NULL, MHI_DEV_DMA_SYNC); + return 0; + } + + /* Adding multiple ring elements */ + if (ring->rd_offset == 0 || (ring->rd_offset > old_offset)) { + /* No wrap-around case */ + host_addr.virt_addr = element; + host_addr.size = size; + mhi_dev_write_to_host(ring->mhi_dev, &host_addr, + ereq, MHI_DEV_DMA_ASYNC); + } else { + /* Wrap-around case - first chunk uses dma sync */ + host_addr.virt_addr = element; + host_addr.size = (ring->ring_size - old_offset) * + sizeof(union mhi_dev_ring_element_type); + mhi_dev_write_to_host(ring->mhi_dev, &host_addr, + NULL, MHI_DEV_DMA_SYNC); + + /* Copy remaining elements */ + if (ring->mhi_dev->use_ipa) + host_addr.host_pa = ring->ring_shadow.host_pa; + else + host_addr.device_va = ring->ring_shadow.device_va; + host_addr.virt_addr = element + (ring->ring_size - old_offset); + host_addr.size = ring->rd_offset * + sizeof(union mhi_dev_ring_element_type); mhi_dev_write_to_host(ring->mhi_dev, &host_addr, - NULL, MHI_DEV_DMA_SYNC); + ereq, MHI_DEV_DMA_ASYNC); + } return 0; } EXPORT_SYMBOL(mhi_dev_add_element); From 95439fdbff182e1da00bf3d50453ab4b7985873e Mon Sep 17 00:00:00 2001 From: Shreyas Narayan Date: Mon, 6 Aug 2018 12:51:40 +0530 Subject: [PATCH 128/392] removed duplicate entry for ext_ec_ref_mux_Ul3 Change-Id: Idf8b319cee438bbb82976ba5818361156379ed31 Signed-off-by: Shreyas Narayan --- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 1c97d4253107..e5f2cfea6e12 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -3231,10 +3231,6 @@ static const struct snd_kcontrol_new ext_ec_ref_mux_ul2 = SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL2 MUX Mux", msm_route_ec_ref_rx_enum[0], msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); -static const struct snd_kcontrol_new ext_ec_ref_mux_ul3 = - SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL3 MUX Mux", - msm_route_ec_ref_rx_enum[0], - msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); static const struct snd_kcontrol_new ext_ec_ref_mux_ul3 = SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL3 MUX Mux", From 982223b411e0f85703efd0cbc0f8e858bdf9d9db Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 3 Nov 2016 20:23:13 +0000 Subject: [PATCH 129/392] BACKPORT: arm64: split thread_info from task stack This patch moves arm64's struct thread_info from the task stack into task_struct. This protects thread_info from corruption in the case of stack overflows, and makes its address harder to determine if stack addresses are leaked, making a number of attacks more difficult. Precise detection and handling of overflow is left for subsequent patches. Largely, this involves changing code to store the task_struct in sp_el0, and acquire the thread_info from the task struct. Core code now implements current_thread_info(), and as noted in this relies on offsetof(task_struct, thread_info) == 0, enforced by core code. This change means that the 'tsk' register used in entry.S now points to a task_struct, rather than a thread_info as it used to. To make this clear, the TI_* field offsets are renamed to TSK_TI_*, with asm-offsets appropriately updated to account for the structural change. Userspace clobbers sp_el0, and we can no longer restore this from the stack. Instead, the current task is cached in a per-cpu variable that we can safely access from early assembly as interrupts are disabled (and we are thus not preemptible). Both secondary entry and idle are updated to stash the sp and task pointer separately. Signed-off-by: Mark Rutland Tested-by: Laura Abbott Cc: AKASHI Takahiro Cc: Andy Lutomirski Cc: Ard Biesheuvel Cc: James Morse Cc: Kees Cook Cc: Suzuki K Poulose Cc: Will Deacon Signed-off-by: Catalin Marinas This is a modification of Mark Rutland's original patch. Guards to check if CONFIG_THREAD_INFO_IN_TASK is used has been inserted. get_current() for when CONFIG_THREAD_INFO_IN_TASK is not used has been added to arch/arm64/include/asm/current.h. Bug: 64672701 Change-Id: Ic5eae344a7c2baea0864f6ae16be1e9c60c0a74a (cherry picked from commit c02433dd6de32f042cf3ffe476746b1115b8c096) Signed-off-by: Zubin Mithra Git-repo: https://android.googlesource.com/kernel/msm Git-commit: fe5800b60e30df67caed77da246150c8d478538b Signed-off-by: Chetan C R --- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/current.h | 27 +++++++++++++++++ arch/arm64/include/asm/smp.h | 3 ++ arch/arm64/include/asm/thread_info.h | 15 +++++++++- arch/arm64/kernel/asm-offsets.c | 14 +++++++-- arch/arm64/kernel/entry.S | 45 ++++++++++++++++++++++++++++ arch/arm64/kernel/head.S | 16 ++++++++++ arch/arm64/kernel/process.c | 22 ++++++++++++++ arch/arm64/kernel/smp.c | 6 ++++ 9 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 arch/arm64/include/asm/current.h diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index ce5afcf34f82..71737b2f9fbb 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -85,6 +85,7 @@ config ARM64 select SPARSE_IRQ select SYSCTL_EXCEPTION_TRACE select HAVE_CONTEXT_TRACKING + select THREAD_INFO_IN_TASK select MSM_JTAGV8 if CORESIGHT_ETMV4 help ARM 64-bit (AArch64) Linux support. diff --git a/arch/arm64/include/asm/current.h b/arch/arm64/include/asm/current.h new file mode 100644 index 000000000000..2e61d21294ba --- /dev/null +++ b/arch/arm64/include/asm/current.h @@ -0,0 +1,27 @@ +#ifndef __ASM_CURRENT_H +#define __ASM_CURRENT_H + +#include + +#include + +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_THREAD_INFO_IN_TASK +struct task_struct; + +static __always_inline struct task_struct *get_current(void) +{ + return (struct task_struct *)read_sysreg(sp_el0); +} +#define current get_current() +#else +#include +#define get_current() (current_thread_info()->task) +#define current get_current() +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_CURRENT_H */ + diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index c78ede618c48..c6dec25b1724 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -56,6 +56,9 @@ asmlinkage void secondary_start_kernel(void); */ struct secondary_data { void *stack; +#ifdef CONFIG_THREAD_INFO_IN_TASK + struct task_struct *task; +#endif }; extern struct secondary_data secondary_data; extern void secondary_entry(void); diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 7193434e165d..756cbf10d5ab 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -46,15 +46,26 @@ typedef unsigned long mm_segment_t; struct thread_info { unsigned long flags; /* low level flags */ mm_segment_t addr_limit; /* address limit */ +#ifndef CONFIG_THREAD_INFO_IN_TASK struct task_struct *task; /* main task structure */ +#endif struct exec_domain *exec_domain; /* execution domain */ #ifdef CONFIG_ARM64_SW_TTBR0_PAN u64 ttbr0; /* saved TTBR0_EL1 */ #endif int preempt_count; /* 0 => preemptable, <0 => bug */ +#ifndef CONFIG_THREAD_INFO_IN_TASK int cpu; /* cpu */ +#endif }; +#ifdef CONFIG_THREAD_INFO_IN_TASK +#define INIT_THREAD_INFO(tsk) \ +{ \ + .preempt_count = INIT_PREEMPT_COUNT, \ + .addr_limit = KERNEL_DS, \ +} +#else #define INIT_THREAD_INFO(tsk) \ { \ .task = &tsk, \ @@ -65,7 +76,6 @@ struct thread_info { } #define init_thread_info (init_thread_union.thread_info) -#define init_stack (init_thread_union.stack) /* * how to get the current stack pointer from C @@ -88,6 +98,9 @@ static inline struct thread_info *current_thread_info(void) return (struct thread_info *)sp_el0; } +#endif + +#define init_stack (init_thread_union.stack) #define thread_saved_pc(tsk) \ ((unsigned long)(tsk->thread.cpu_context.pc)) diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index a865573461e1..1e5c7d0430ea 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -34,12 +34,17 @@ int main(void) { DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); BLANK(); +#ifdef CONFIG_THREAD_INFO_IN_TASK + DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags)); + DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count)); + DEFINE(TSK_TI_ADDR_LIMIT, offsetof(struct task_struct, thread_info.addr_limit)); + DEFINE(TSK_STACK, offsetof(struct task_struct, stack)); +#else DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit)); - DEFINE(TI_TASK, offsetof(struct thread_info, task)); DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain)); - DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); +#endif #ifdef CONFIG_ARM64_SW_TTBR0_PAN DEFINE(TSK_TI_TTBR0, offsetof(struct thread_info, ttbr0)); #endif @@ -113,6 +118,11 @@ int main(void) DEFINE(TZ_MINWEST, offsetof(struct timezone, tz_minuteswest)); DEFINE(TZ_DSTTIME, offsetof(struct timezone, tz_dsttime)); BLANK(); +#ifdef CONFIG_THREAD_INFO_IN_TASK + DEFINE(CPU_BOOT_STACK, offsetof(struct secondary_data, stack)); + DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task)); + BLANK(); +#endif #ifdef CONFIG_KVM_ARM_HOST DEFINE(VCPU_CONTEXT, offsetof(struct kvm_vcpu, arch.ctxt)); DEFINE(CPU_GP_REGS, offsetof(struct kvm_cpu_context, gp_regs)); diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 709f8cf0af8e..07403f503818 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -116,18 +116,31 @@ alternative_else_nop_endif .if \el == 0 mrs x21, sp_el0 +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr_this_cpu tsk, __entry_task, x20 // Ensure MDSCR_EL1.SS is clear, + ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug +#else mov tsk, sp and tsk, tsk, #~(THREAD_SIZE - 1) // Ensure MDSCR_EL1.SS is clear, ldr x19, [tsk, #TI_FLAGS] // since we can unmask debug +#endif disable_step_tsk x19, x20 // exceptions when scheduling. .else add x21, sp, #S_FRAME_SIZE get_thread_info tsk /* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */ +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x20, [tsk, #TSK_TI_ADDR_LIMIT] +#else ldr x20, [tsk, #TI_ADDR_LIMIT] +#endif str x20, [sp, #S_ORIG_ADDR_LIMIT] mov x20, #TASK_SIZE_64 +#ifdef CONFIG_THREAD_INFO_IN_TASK + str x20, [tsk, #TSK_TI_ADDR_LIMIT] +#else str x20, [tsk, #TI_ADDR_LIMIT] +#endif ALTERNATIVE(nop, SET_PSTATE_UAO(0), ARM64_HAS_UAO, CONFIG_ARM64_UAO) .endif /* \el == 0 */ mrs x22, elr_el1 @@ -189,7 +202,11 @@ alternative_else_nop_endif .if \el != 0 /* Restore the task's original addr_limit. */ ldr x20, [sp, #S_ORIG_ADDR_LIMIT] +#ifdef CONFIG_THREAD_INFO_IN_TASK + str x20, [tsk, #TSK_TI_ADDR_LIMIT] +#else str x20, [tsk, #TI_ADDR_LIMIT] +#endif /* No need to restore UAO, it will be restored from SPSR_EL1 */ .endif @@ -487,9 +504,17 @@ el1_irq: #ifdef CONFIG_PREEMPT get_thread_info tsk +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr w24, [tsk, #TSK_TI_PREEMPT] // get preempt count +#else ldr w24, [tsk, #TI_PREEMPT] // get preempt count +#endif cbnz w24, 1f // preempt count != 0 +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x0, [tsk, #TSK_TI_FLAGS] // get flags +#else ldr x0, [tsk, #TI_FLAGS] // get flags +#endif tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling? bl el1_preempt 1: @@ -504,7 +529,11 @@ ENDPROC(el1_irq) el1_preempt: mov x24, lr 1: bl preempt_schedule_irq // irq en/disable is done inside +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x0, [tsk, #TSK_TI_FLAGS] // get new tasks TI_FLAGS +#else ldr x0, [tsk, #TI_FLAGS] // get new tasks TI_FLAGS +#endif tbnz x0, #TIF_NEED_RESCHED, 1b // needs rescheduling? ret x24 #endif @@ -771,8 +800,12 @@ ENTRY(cpu_switch_to) mov v15.16b, v15.16b #endif mov sp, x9 +#ifdef CONFIG_THREAD_INFO_IN_TASK + msr sp_el0, x1 +#else and x9, x9, #~(THREAD_SIZE - 1) msr sp_el0, x9 +#endif ret ENDPROC(cpu_switch_to) @@ -783,7 +816,11 @@ ENDPROC(cpu_switch_to) ret_fast_syscall: disable_irq // disable interrupts str x0, [sp, #S_X0] // returned x0 +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for syscall tracing +#else ldr x1, [tsk, #TI_FLAGS] // re-check for syscall tracing +#endif and x2, x1, #_TIF_SYSCALL_WORK cbnz x2, ret_fast_syscall_trace and x2, x1, #_TIF_WORK_MASK @@ -815,7 +852,11 @@ work_resched: */ ret_to_user: disable_irq // disable interrupts +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x1, [tsk, #TSK_TI_FLAGS] +#else ldr x1, [tsk, #TI_FLAGS] +#endif and x2, x1, #_TIF_WORK_MASK cbnz x2, work_pending enable_step_tsk x1, x2 @@ -848,7 +889,11 @@ el0_svc_naked: // compat entry point enable_dbg_and_irq ct_user_exit 1 +#ifdef CONFIG_THREAD_INFO_IN_TASK + ldr x16, [tsk, #TSK_TI_FLAGS] // check for syscall hooks +#else ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks +#endif tst x16, #_TIF_SYSCALL_WORK b.ne __sys_trace cmp scno, sc_nr // check upper syscall limit diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index d3636fc48805..bcf174f26937 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -456,10 +456,18 @@ __mmap_switched: bl __pi_memset dsb ishst // Make zero page visible to PTW +#ifdef CONFIG_THREAD_INFO_IN_TASK + adrp x4, init_thread_union + add sp, x4, #THREAD_SIZE + adr_l x5, init_task + msr sp_el0, x5 // Save thread_info +#else adr_l sp, initial_sp, x4 mov x4, sp and x4, x4, #~(THREAD_SIZE - 1) msr sp_el0, x4 // Save thread_info +#endif + str_l x21, __fdt_pointer, x5 // Save FDT pointer str_l x24, memstart_addr, x6 // Save PHYS_OFFSET mov x29, #0 @@ -641,10 +649,18 @@ ENTRY(secondary_startup) ENDPROC(secondary_startup) ENTRY(__secondary_switched) +#ifdef CONFIG_THREAD_INFO_IN_TASK + adr_l x0, secondary_data + ldr x1, [x0, #CPU_BOOT_STACK] // get secondary_data.stack + mov sp, x1 + ldr x2, [x0, #CPU_BOOT_TASK] + msr sp_el0, x2 +#else ldr x0, [x21] // get secondary_data.stack mov sp, x0 and x0, x0, #~(THREAD_SIZE - 1) msr sp_el0, x0 // save thread_info +#endif mov x29, #0 b secondary_start_kernel ENDPROC(__secondary_switched) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index f11d7e4b375b..eff22af8c01b 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -44,6 +44,9 @@ #include #include +#ifdef CONFIG_THREAD_INFO_IN_TASK +#include +#endif #include #include #include @@ -382,6 +385,22 @@ static void uao_thread_switch(struct task_struct *next) } } +#ifdef CONFIG_THREAD_INFO_IN_TASK +/* + * We store our current task in sp_el0, which is clobbered by userspace. Keep a + * shadow copy so that we can restore this upon entry from userspace. + * + * This is *only* for exception entry from EL0, and is not valid until we + * __switch_to() a user task. + */ +DEFINE_PER_CPU(struct task_struct *, __entry_task); + +static void entry_task_switch(struct task_struct *next) +{ + __this_cpu_write(__entry_task, next); +} +#endif + /* * Thread switching. */ @@ -394,6 +413,9 @@ struct task_struct *__switch_to(struct task_struct *prev, tls_thread_switch(next); hw_breakpoint_thread_switch(next); contextidr_thread_switch(next); +#ifdef CONFIG_THREAD_INFO_IN_TASK + entry_task_switch(next); +#endif uao_thread_switch(next); /* diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 152ad0f99ce4..d51ae08268c4 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -97,6 +97,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) * We need to tell the secondary core where to find its stack and the * page tables. */ +#ifdef CONFIG_THREAD_INFO_IN_TASK + secondary_data.task = idle; +#endif secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; __flush_dcache_area(&secondary_data, sizeof(secondary_data)); @@ -120,6 +123,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) pr_err("CPU%u: failed to boot: %d\n", cpu, ret); } +#ifdef CONFIG_THREAD_INFO_IN_TASK + secondary_data.task = NULL; +#endif secondary_data.stack = NULL; return ret; From e425d3cddb1504dcf951a6075922813b74f9e0b0 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 20 Dec 2017 14:28:25 -0800 Subject: [PATCH 130/392] crypto: pcrypt - fix freeing pcrypt instances pcrypt is using the old way of freeing instances, where the ->free() method specified in the 'struct crypto_template' is passed a pointer to the 'struct crypto_instance'. But the crypto_instance is being kfree()'d directly, which is incorrect because the memory was actually allocated as an aead_instance, which contains the crypto_instance at a nonzero offset. Thus, the wrong pointer was being kfree()'d. Fix it by switching to the new way to free aead_instance's where the ->free() method is specified in the aead_instance itself. Change-Id: I4e7ca9d5e450708b0b02129d99d7044a534c1144 Reported-by: syzbot Fixes: 0496f56065e0 ("crypto: pcrypt - Add support for new AEAD interface") Cc: # v4.2+ Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Git-repo: Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Git-commit: d76c68109f37cb85b243a1cf0f40313afd2bae68 [cravin@codeaurora.org : Resolved minor conflict] Signed-off-by: Srinivasa Rao Kuppala --- crypto/pcrypt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index c305d4112735..bd5f14ea528e 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -306,6 +306,14 @@ static void pcrypt_aead_exit_tfm(struct crypto_tfm *tfm) crypto_free_aead(ctx->child); } +static void pcrypt_free(struct crypto_instance *inst) +{ + struct pcrypt_instance_ctx *ctx = crypto_instance_ctx(inst); + + crypto_drop_spawn(&ctx->spawn); + kfree(inst); +} + static struct crypto_instance *pcrypt_alloc_instance(struct crypto_alg *alg) { struct crypto_instance *inst; @@ -375,6 +383,7 @@ static struct crypto_instance *pcrypt_alloc_aead(struct rtattr **tb, inst->alg.cra_aead.encrypt = pcrypt_aead_encrypt; inst->alg.cra_aead.decrypt = pcrypt_aead_decrypt; inst->alg.cra_aead.givencrypt = pcrypt_aead_givencrypt; + inst->tmpl->free = pcrypt_free; out_put_alg: crypto_mod_put(alg); @@ -397,14 +406,6 @@ static struct crypto_instance *pcrypt_alloc(struct rtattr **tb) return ERR_PTR(-EINVAL); } -static void pcrypt_free(struct crypto_instance *inst) -{ - struct pcrypt_instance_ctx *ctx = crypto_instance_ctx(inst); - - crypto_drop_spawn(&ctx->spawn); - kfree(inst); -} - static int pcrypt_cpumask_change_notify(struct notifier_block *self, unsigned long val, void *data) { @@ -517,7 +518,6 @@ static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt) static struct crypto_template pcrypt_tmpl = { .name = "pcrypt", .alloc = pcrypt_alloc, - .free = pcrypt_free, .module = THIS_MODULE, }; From 809b89921a56fc8bb839c54fcae560e5aa09abdc Mon Sep 17 00:00:00 2001 From: Jhansi Konathala Date: Mon, 11 Jun 2018 18:20:27 +0530 Subject: [PATCH 131/392] SoC: msm: msm_audio_ion: Add the scm call Add upgraded version of audio memory protection scm API call in msm_audio_ion_probe to protect audio ion memory region. Change-Id: I48ade6e937357858ab4aaafc02f15a1d8b61f2b2 Signed-off-by: Jhansi Konathala --- drivers/soc/qcom/qdsp6v2/msm_audio_ion.c | 25 ++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c index 91395fdff16a..81b38023f70f 100644 --- a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c +++ b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -44,6 +44,7 @@ #define MSM_AUDIO_SMMU_SID_OFFSET 32 #define TZBSP_MEM_PROTECT_AUDIO_CMD_ID 0x00000005 +#define TZBSP_MEM_PROTECT_AUDIO_CMD_ID_2 0x00000006 struct addr_range { dma_addr_t start; @@ -811,11 +812,12 @@ u32 msm_audio_populate_upper_32_bits(ion_phys_addr_t pa) return upper_32_bits(pa); } -static void msm_audio_protect_memory_region(struct device *dev) +static int msm_audio_protect_memory_region(struct device *dev) { int ret = 0; unsigned long size = 0; phys_addr_t phys_addr = 0; + struct scm_desc desc2 = {0}; struct tz_mem_protect_cmd_buf desc = {0}; struct tz_resp resp = {0}; @@ -825,13 +827,24 @@ static void msm_audio_protect_memory_region(struct device *dev) pr_debug("%s: cma_audio_mem_addr %pK with size %lu\n", __func__, &phys_addr, size); - desc.phys_addr = phys_addr; - desc.size = size; - ret = scm_call(SCM_SVC_MP, TZBSP_MEM_PROTECT_AUDIO_CMD_ID, - (void *)&desc , sizeof(desc), (void *)&resp, sizeof(resp)); + desc2.args[0] = desc.phys_addr = phys_addr; + desc2.args[1] = desc.size = size; + desc2.arginfo = SCM_ARGS(2); + if (!is_scm_armv8()) { + ret = scm_call(SCM_SVC_MP, TZBSP_MEM_PROTECT_AUDIO_CMD_ID, + (void *)&desc , sizeof(desc), + (void *)&resp, sizeof(resp)); + } else { + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, + TZBSP_MEM_PROTECT_AUDIO_CMD_ID_2), &desc2); + resp.ret = desc2.ret[0]; + } if (ret < 0) pr_err("%s: SCM call failed, scm_call_ret %d tz_resp %d\n", __func__, ret, resp.ret); + if (!is_scm_armv8()) + return ret; + return desc2.ret[0]; } static int msm_audio_ion_probe(struct platform_device *pdev) From bc23c336c3cb3657e8205f890913bd5753c4bcda Mon Sep 17 00:00:00 2001 From: Paras Nagda Date: Tue, 29 May 2018 17:50:35 +0530 Subject: [PATCH 132/392] msm: vidc: Increase minimum input buffer count for HEVC decode Increase minimum input buffer count for HEVC decode to 5 to avoid hang when the DPB is not full and FW keeps waiting for FTB although sufficient ETB are being queued. Change-Id: Id344cd896aeac46765e250e715d14a6c835b4221 Signed-off-by: Paras Nagda --- drivers/media/platform/msm/vidc/msm_vdec.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 86b7b1b6f6c0..579f032949a1 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -22,6 +22,7 @@ #define MSM_VDEC_DVC_NAME "msm_vdec_8974" #define MIN_NUM_OUTPUT_BUFFERS 4 #define MIN_NUM_OUTPUT_BUFFERS_VP9 6 +#define MIN_NUM_OUTPUT_BUFFERS_HEVC 5 #define MIN_NUM_CAPTURE_BUFFERS 6 #define MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS 1 #define MAX_NUM_OUTPUT_BUFFERS VB2_MAX_FRAME @@ -1494,6 +1495,10 @@ static int msm_vdec_queue_setup(struct vb2_queue *q, V4L2_PIX_FMT_VP9 && *num_buffers < MIN_NUM_OUTPUT_BUFFERS_VP9) *num_buffers = MIN_NUM_OUTPUT_BUFFERS_VP9; + else if (inst->fmts[OUTPUT_PORT].fourcc == + V4L2_PIX_FMT_HEVC && + *num_buffers < MIN_NUM_OUTPUT_BUFFERS_HEVC) + *num_buffers = MIN_NUM_OUTPUT_BUFFERS_HEVC; for (i = 0; i < *num_planes; i++) { sizes[i] = get_frame_size(inst, From 3dc6a920a53a06704502ddce1adf8513f0103553 Mon Sep 17 00:00:00 2001 From: Paras Nagda Date: Fri, 3 Aug 2018 19:31:27 +0530 Subject: [PATCH 133/392] msm: vidc: remove redundant init_completion() calls Video driver is doing init_completion() for all completion events in msm_vidc_initialize_core() and msm_vidc_open(). So there is no need of calling init_completion() again before waiting for completion event and hence remove them. Change-Id: Iedd9c4c0763c29b26e91e261d9a8d0e4e24b7bb2 Signed-off-by: Maheshwar Ajja Signed-off-by: Paras Nagda --- .../media/platform/msm/vidc/msm_vidc_common.c | 22 +------------------ drivers/media/platform/msm/vidc/venus_hfi.c | 7 +----- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 73c26bb60fac..7245f2a3322d 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2449,7 +2449,6 @@ static int msm_comm_session_abort(struct msm_vidc_inst *inst) } hdev = inst->core->device; abort_completion = SESSION_MSG_INDEX(HAL_SESSION_ABORT_DONE); - init_completion(&inst->completions[abort_completion]); rc = call_hfi_op(hdev, session_abort, (void *)inst->session); if (rc) { @@ -2608,8 +2607,6 @@ static int msm_comm_init_core(struct msm_vidc_inst *inst) __func__); } - init_completion(&core->completions - [SYS_MSG_INDEX(HAL_SYS_INIT_DONE)]); rc = call_hfi_op(hdev, core_init, hdev->hfi_device_data); if (rc) { dprintk(VIDC_ERR, "Failed to init core, id = %d\n", @@ -2713,8 +2710,6 @@ static int msm_comm_session_init(int flipped_state, dprintk(VIDC_ERR, "Invalid session\n"); return -EINVAL; } - init_completion( - &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_INIT_DONE)]); rc = call_hfi_op(hdev, session_init, hdev->hfi_device_data, inst, get_hal_domain(inst->session_type), @@ -2852,8 +2847,6 @@ static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst) inst, inst->state); goto exit; } - init_completion( - &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_START_DONE)]); rc = call_hfi_op(hdev, session_start, (void *) inst->session); if (rc) { dprintk(VIDC_ERR, @@ -2883,8 +2876,6 @@ static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst) goto exit; } dprintk(VIDC_DBG, "Send Stop to hal\n"); - init_completion( - &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_STOP_DONE)]); rc = call_hfi_op(hdev, session_stop, (void *) inst->session); if (rc) { dprintk(VIDC_ERR, "Failed to send stop\n"); @@ -2914,8 +2905,6 @@ static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst) } dprintk(VIDC_DBG, "Send release res to hal\n"); - init_completion(&inst->completions[ - SESSION_MSG_INDEX(HAL_SESSION_RELEASE_RESOURCE_DONE)]); rc = call_hfi_op(hdev, session_release_res, (void *) inst->session); if (rc) { dprintk(VIDC_ERR, @@ -2946,8 +2935,6 @@ static int msm_comm_session_close(int flipped_state, } dprintk(VIDC_DBG, "Send session close to hal\n"); - init_completion( - &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_END_DONE)]); rc = call_hfi_op(hdev, session_end, (void *) inst->session); if (rc) { dprintk(VIDC_ERR, @@ -3985,8 +3972,6 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype, } mutex_unlock(&inst->sync_lock); - init_completion(&inst->completions[ - SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO)]); switch (ptype) { case HAL_PARAM_PROFILE_LEVEL_CURRENT: case HAL_CONFIG_VDEC_ENTROPY: @@ -4210,8 +4195,6 @@ int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst, if (inst->state != MSM_VIDC_CORE_INVALID && core->state != VIDC_CORE_INVALID) { buffer_info.response_required = true; - init_completion(&inst->completions[SESSION_MSG_INDEX - (HAL_SESSION_RELEASE_BUFFER_DONE)]); rc = call_hfi_op(hdev, session_release_buffers, (void *)inst->session, &buffer_info); if (rc) { @@ -4282,9 +4265,6 @@ int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst) if (inst->state != MSM_VIDC_CORE_INVALID && core->state != VIDC_CORE_INVALID) { buffer_info.response_required = true; - init_completion( - &inst->completions[SESSION_MSG_INDEX - (HAL_SESSION_RELEASE_BUFFER_DONE)]); rc = call_hfi_op(hdev, session_release_buffers, (void *)inst->session, &buffer_info); if (rc) { diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 081459df9016..2e1bd37dda52 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -937,8 +937,6 @@ static int __core_set_resource(struct venus_hfi_device *device, return rc; } -static DECLARE_COMPLETION(release_resources_done); - static int __alloc_imem(struct venus_hfi_device *device, unsigned long size) { struct imem *imem = NULL; @@ -2158,8 +2156,6 @@ static int venus_hfi_core_init(void *device) dev = device; mutex_lock(&dev->lock); - init_completion(&release_resources_done); - rc = __load_fw(dev); if (rc) { dprintk(VIDC_ERR, "Failed to load Venus FW\n"); @@ -3461,7 +3457,6 @@ static int __response_handler(struct venus_hfi_device *device) break; case HAL_SYS_RELEASE_RESOURCE_DONE: dprintk(VIDC_DBG, "Received SYS_RELEASE_RESOURCE\n"); - complete(&release_resources_done); break; case HAL_SYS_INIT_DONE: dprintk(VIDC_DBG, "Received SYS_INIT_DONE\n"); From 0b1a3b5b05bf80ff2ca827e6475b7e16ff87e6c0 Mon Sep 17 00:00:00 2001 From: Vishwanath Raju K Date: Tue, 10 Jul 2018 17:51:36 +0530 Subject: [PATCH 134/392] ARM: dts: msm: Add common CMA device configuration for sdx20 TZ expects firmware regions under 256MB. BG firmware region is allocated from common CMA region. Add common CMA configuration and restrict it within 256MB region for sdx20. Change-Id: I0b041520948878bc73719d84ab0ed0099fb7a54f Signed-off-by: Vishwanath Raju K --- arch/arm/boot/dts/qcom/mdm9650.dtsi | 2 +- arch/arm/boot/dts/qcom/sdx20.dtsi | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/mdm9650.dtsi b/arch/arm/boot/dts/qcom/mdm9650.dtsi index 45084064bbfc..94e02dc3239f 100644 --- a/arch/arm/boot/dts/qcom/mdm9650.dtsi +++ b/arch/arm/boot/dts/qcom/mdm9650.dtsi @@ -22,7 +22,7 @@ <286 0x10000>, <283 0x10000>, <359 0x10000>; interrupt-parent = <&intc>; - reserved-memory { + reserved_mem: reserved-memory { #address-cells = <1>; #size-cells = <1>; ranges; diff --git a/arch/arm/boot/dts/qcom/sdx20.dtsi b/arch/arm/boot/dts/qcom/sdx20.dtsi index cd475d34720f..6059ed7278f6 100644 --- a/arch/arm/boot/dts/qcom/sdx20.dtsi +++ b/arch/arm/boot/dts/qcom/sdx20.dtsi @@ -39,6 +39,17 @@ reg = <0x88000000 0x7300000>; }; +&reserved_mem { + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0x90000000>; + reusable; + alignment = <0 0x400000>; + size = <0 0xc00000>; + linux,cma-default; + }; +}; + &soc { /* SD card 2.95 V supply */ sdc_vreg: sdc_vreg { From 113859ff99263ae2fee8c88680a3a29734951ce2 Mon Sep 17 00:00:00 2001 From: AnilKumar Chimata Date: Thu, 12 Jul 2018 17:45:32 +0530 Subject: [PATCH 135/392] defconfig: Remove FIPS flag from config Remove FIPS flag from msmcortex defconfig which is not needed. Change-Id: Ie02316b8dcc494d3c6298a936007f276b95f7817 Signed-off-by: AnilKumar Chimata --- arch/arm/configs/msmcortex_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig index 4e6b91757b5f..94fbc36d8b14 100644 --- a/arch/arm/configs/msmcortex_defconfig +++ b/arch/arm/configs/msmcortex_defconfig @@ -669,7 +669,6 @@ CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y -CONFIG_FIPS_ENABLE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y From 4361f73aad0243f57acef79eaf2508ab223e9745 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 24 Jul 2018 19:13:31 -0400 Subject: [PATCH 136/392] tracing: Fix double free of event_trigger_data commit 1863c387259b629e4ebfb255495f67cd06aa229b upstream. Running the following: # cd /sys/kernel/debug/tracing # echo 500000 > buffer_size_kb [ Or some other number that takes up most of memory ] # echo snapshot > events/sched/sched_switch/trigger Triggers the following bug: ------------[ cut here ]------------ kernel BUG at mm/slub.c:296! invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC PTI CPU: 6 PID: 6878 Comm: bash Not tainted 4.18.0-rc6-test+ #1066 Hardware name: Hewlett-Packard HP Compaq Pro 6300 SFF/339A, BIOS K01 v03.03 07/14/2016 RIP: 0010:kfree+0x16c/0x180 Code: 05 41 0f b6 72 51 5b 5d 41 5c 4c 89 d7 e9 ac b3 f8 ff 48 89 d9 48 89 da 41 b8 01 00 00 00 5b 5d 41 5c 4c 89 d6 e9 f4 f3 ff ff <0f> 0b 0f 0b 48 8b 3d d9 d8 f9 00 e9 c1 fe ff ff 0f 1f 40 00 0f 1f RSP: 0018:ffffb654436d3d88 EFLAGS: 00010246 RAX: ffff91a9d50f3d80 RBX: ffff91a9d50f3d80 RCX: ffff91a9d50f3d80 RDX: 00000000000006a4 RSI: ffff91a9de5a60e0 RDI: ffff91a9d9803500 RBP: ffffffff8d267c80 R08: 00000000000260e0 R09: ffffffff8c1a56be R10: fffff0d404543cc0 R11: 0000000000000389 R12: ffffffff8c1a56be R13: ffff91a9d9930e18 R14: ffff91a98c0c2890 R15: ffffffff8d267d00 FS: 00007f363ea64700(0000) GS:ffff91a9de580000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055c1cacc8e10 CR3: 00000000d9b46003 CR4: 00000000001606e0 Call Trace: event_trigger_callback+0xee/0x1d0 event_trigger_write+0xfc/0x1a0 __vfs_write+0x33/0x190 ? handle_mm_fault+0x115/0x230 ? _cond_resched+0x16/0x40 vfs_write+0xb0/0x190 ksys_write+0x52/0xc0 do_syscall_64+0x5a/0x160 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x7f363e16ab50 Code: 73 01 c3 48 8b 0d 38 83 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 83 3d 79 db 2c 00 00 75 10 b8 01 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 1e e3 01 00 48 89 04 24 RSP: 002b:00007fff9a4c6378 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 0000000000000009 RCX: 00007f363e16ab50 RDX: 0000000000000009 RSI: 000055c1cacc8e10 RDI: 0000000000000001 RBP: 000055c1cacc8e10 R08: 00007f363e435740 R09: 00007f363ea64700 R10: 0000000000000073 R11: 0000000000000246 R12: 0000000000000009 R13: 0000000000000001 R14: 00007f363e4345e0 R15: 00007f363e4303c0 Modules linked in: ip6table_filter ip6_tables snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_seq snd_seq_device i915 snd_pcm snd_timer i2c_i801 snd soundcore i2c_algo_bit drm_kms_helper 86_pkg_temp_thermal video kvm_intel kvm irqbypass wmi e1000e ---[ end trace d301afa879ddfa25 ]--- The cause is because the register_snapshot_trigger() call failed to allocate the snapshot buffer, and then called unregister_trigger() which freed the data that was passed to it. Then on return to the function that called register_snapshot_trigger(), as it sees it failed to register, it frees the trigger_data again and causes a double free. By calling event_trigger_init() on the trigger_data (which only ups the reference counter for it), and then event_trigger_free() afterward, the trigger_data would not get freed by the registering trigger function as it would only up and lower the ref count for it. If the register trigger function fails, then the event_trigger_free() called after it will free the trigger data normally. Link: http://lkml.kernel.org/r/20180724191331.738eb819@gandalf.local.home Cc: stable@vger.kerne.org Fixes: 93e31ffbf417 ("tracing: Add 'snapshot' event trigger command") Reported-by: Masami Hiramatsu Reviewed-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_events_trigger.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index b743e758241e..f10a833664c1 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -663,6 +663,8 @@ event_trigger_callback(struct event_command *cmd_ops, goto out_free; out_reg: + /* Up the trigger_data count to make sure reg doesn't free it on failure */ + event_trigger_init(trigger_ops, trigger_data); ret = cmd_ops->reg(glob, trigger_ops, trigger_data, file); /* * The above returns on success the # of functions enabled, @@ -670,11 +672,13 @@ event_trigger_callback(struct event_command *cmd_ops, * Consider no functions a failure too. */ if (!ret) { + cmd_ops->unreg(glob, trigger_ops, trigger_data, file); ret = -ENOENT; - goto out_free; - } else if (ret < 0) - goto out_free; - ret = 0; + } else if (ret > 0) + ret = 0; + + /* Down the counter of trigger_data or free it if not used anymore */ + event_trigger_free(trigger_ops, trigger_data); out: return ret; From 606ce67d88427994b5add25c0ab27bb4ccd44cd9 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 25 Jul 2018 16:02:06 -0400 Subject: [PATCH 137/392] tracing: Fix possible double free in event_enable_trigger_func() commit 15cc78644d0075e76d59476a4467e7143860f660 upstream. There was a case that triggered a double free in event_trigger_callback() due to the called reg() function freeing the trigger_data and then it getting freed again by the error return by the caller. The solution there was to up the trigger_data ref count. Code inspection found that event_enable_trigger_func() has the same issue, but is not as easy to trigger (requires harder to trigger failures). It needs to be solved slightly different as it needs more to clean up when the reg() function fails. Link: http://lkml.kernel.org/r/20180725124008.7008e586@gandalf.local.home Cc: stable@vger.kernel.org Fixes: 7862ad1846e99 ("tracing: Add 'enable_event' and 'disable_event' event trigger commands") Reivewed-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_events_trigger.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index f10a833664c1..a958d3397a52 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -1231,6 +1231,9 @@ event_enable_trigger_func(struct event_command *cmd_ops, goto out; } + /* Up the trigger_data count to make sure nothing frees it on failure */ + event_trigger_init(trigger_ops, trigger_data); + if (trigger) { number = strsep(&trigger, ":"); @@ -1281,6 +1284,7 @@ event_enable_trigger_func(struct event_command *cmd_ops, goto out_disable; /* Just return zero, not the number of enabled functions */ ret = 0; + event_trigger_free(trigger_ops, trigger_data); out: return ret; @@ -1291,7 +1295,7 @@ event_enable_trigger_func(struct event_command *cmd_ops, out_free: if (cmd_ops->set_filter) cmd_ops->set_filter(NULL, trigger_data, NULL); - kfree(trigger_data); + event_trigger_free(trigger_ops, trigger_data); kfree(enable_data); goto out; } From 15165b72aa41f623e1519e03e5e1de9ee92cad73 Mon Sep 17 00:00:00 2001 From: Artem Savkov Date: Wed, 25 Jul 2018 16:20:38 +0200 Subject: [PATCH 138/392] tracing/kprobes: Fix trace_probe flags on enable_trace_kprobe() failure commit 57ea2a34adf40f3a6e88409aafcf803b8945619a upstream. If enable_trace_kprobe fails to enable the probe in enable_k(ret)probe it returns an error, but does not unset the tp flags it set previously. This results in a probe being considered enabled and failures like being unable to remove the probe through kprobe_events file since probes_open() expects every probe to be disabled. Link: http://lkml.kernel.org/r/20180725102826.8300-1-asavkov@redhat.com Link: http://lkml.kernel.org/r/20180725142038.4765-1-asavkov@redhat.com Cc: Ingo Molnar Cc: stable@vger.kernel.org Fixes: 41a7dd420c57 ("tracing/kprobes: Support ftrace_event_file base multibuffer") Acked-by: Masami Hiramatsu Reviewed-by: Josh Poimboeuf Signed-off-by: Artem Savkov Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_kprobe.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 46f2db093360..669609756720 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -361,11 +361,10 @@ static struct trace_kprobe *find_trace_kprobe(const char *event, static int enable_trace_kprobe(struct trace_kprobe *tk, struct ftrace_event_file *file) { + struct event_file_link *link; int ret = 0; if (file) { - struct event_file_link *link; - link = kmalloc(sizeof(*link), GFP_KERNEL); if (!link) { ret = -ENOMEM; @@ -385,6 +384,16 @@ enable_trace_kprobe(struct trace_kprobe *tk, struct ftrace_event_file *file) else ret = enable_kprobe(&tk->rp.kp); } + + if (ret) { + if (file) { + list_del_rcu(&link->list); + kfree(link); + tk->tp.flags &= ~TP_FLAG_TRACE; + } else { + tk->tp.flags &= ~TP_FLAG_PROFILE; + } + } out: return ret; } From 490106d9760e34ec0f85139e8ec900f2aa6974e9 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 25 Jul 2018 22:28:56 -0400 Subject: [PATCH 139/392] tracing: Quiet gcc warning about maybe unused link variable commit 2519c1bbe38d7acacc9aacba303ca6f97482ed53 upstream. Commit 57ea2a34adf4 ("tracing/kprobes: Fix trace_probe flags on enable_trace_kprobe() failure") added an if statement that depends on another if statement that gcc doesn't see will initialize the "link" variable and gives the warning: "warning: 'link' may be used uninitialized in this function" It is really a false positive, but to quiet the warning, and also to make sure that it never actually is used uninitialized, initialize the "link" variable to NULL and add an if (!WARN_ON_ONCE(!link)) where the compiler thinks it could be used uninitialized. Cc: stable@vger.kernel.org Fixes: 57ea2a34adf4 ("tracing/kprobes: Fix trace_probe flags on enable_trace_kprobe() failure") Reported-by: kbuild test robot Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_kprobe.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 669609756720..e052395ba83a 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -361,7 +361,7 @@ static struct trace_kprobe *find_trace_kprobe(const char *event, static int enable_trace_kprobe(struct trace_kprobe *tk, struct ftrace_event_file *file) { - struct event_file_link *link; + struct event_file_link *link = NULL; int ret = 0; if (file) { @@ -387,7 +387,9 @@ enable_trace_kprobe(struct trace_kprobe *tk, struct ftrace_event_file *file) if (ret) { if (file) { - list_del_rcu(&link->list); + /* Notice the if is true on not WARN() */ + if (!WARN_ON_ONCE(!link)) + list_del_rcu(&link->list); kfree(link); tk->tp.flags &= ~TP_FLAG_TRACE; } else { From da2858dce9a74580d2ce234fe6da99e22eef5b1a Mon Sep 17 00:00:00 2001 From: Zhouyang Jia Date: Mon, 11 Jun 2018 16:18:40 +0800 Subject: [PATCH 140/392] ALSA: emu10k1: add error handling for snd_ctl_add [ Upstream commit 6d531e7b972cb62ded011c2dfcc2d9f72ea6c421 ] When snd_ctl_add fails, the lack of error-handling code may cause unexpected results. This patch adds error-handling code after calling snd_ctl_add. Signed-off-by: Zhouyang Jia Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/pci/emu10k1/emupcm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 36f0b8646417..0e6dd2464e81 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1875,7 +1875,9 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device, if (!kctl) return -ENOMEM; kctl->id.device = device; - snd_ctl_add(emu->card, kctl); + err = snd_ctl_add(emu->card, kctl); + if (err < 0) + return err; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); From 942172d5ffc63c4bd16fa86812a9623701e8cdac Mon Sep 17 00:00:00 2001 From: Zhouyang Jia Date: Mon, 11 Jun 2018 16:04:06 +0800 Subject: [PATCH 141/392] ALSA: fm801: add error handling for snd_ctl_add [ Upstream commit ef1ffbe7889e99f5b5cccb41c89e5c94f50f3218 ] When snd_ctl_add fails, the lack of error-handling code may cause unexpected results. This patch adds error-handling code after calling snd_ctl_add. Signed-off-by: Zhouyang Jia Acked-by: Andy Shevchenko Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/pci/fm801.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index c5038303a126..0fd39b2f75cc 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1070,11 +1070,19 @@ static int snd_fm801_mixer(struct fm801 *chip) if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_sec)) < 0) return err; } - for (i = 0; i < FM801_CONTROLS; i++) - snd_ctl_add(chip->card, snd_ctl_new1(&snd_fm801_controls[i], chip)); + for (i = 0; i < FM801_CONTROLS; i++) { + err = snd_ctl_add(chip->card, + snd_ctl_new1(&snd_fm801_controls[i], chip)); + if (err < 0) + return err; + } if (chip->multichannel) { - for (i = 0; i < FM801_CONTROLS_MULTI; i++) - snd_ctl_add(chip->card, snd_ctl_new1(&snd_fm801_controls_multi[i], chip)); + for (i = 0; i < FM801_CONTROLS_MULTI; i++) { + err = snd_ctl_add(chip->card, + snd_ctl_new1(&snd_fm801_controls_multi[i], chip)); + if (err < 0) + return err; + } } return 0; } From f6581cff8a28891c64128e88db36f04a04be11ba Mon Sep 17 00:00:00 2001 From: Chintan Pandya Date: Thu, 7 Jun 2018 17:06:50 -0700 Subject: [PATCH 142/392] mm: vmalloc: avoid racy handling of debugobjects in vunmap [ Upstream commit f3c01d2f3ade6790db67f80fef60df84424f8964 ] Currently, __vunmap flow is, 1) Release the VM area 2) Free the debug objects corresponding to that vm area. This leave some race window open. 1) Release the VM area 1.5) Some other client gets the same vm area 1.6) This client allocates new debug objects on the same vm area 2) Free the debug objects corresponding to this vm area. Here, we actually free 'other' client's debug objects. Fix this by freeing the debug objects first and then releasing the VM area. Link: http://lkml.kernel.org/r/1523961828-9485-2-git-send-email-cpandya@codeaurora.org Signed-off-by: Chintan Pandya Reviewed-by: Andrew Morton Cc: Ard Biesheuvel Cc: Byungchul Park Cc: Catalin Marinas Cc: Florian Fainelli Cc: Johannes Weiner Cc: Laura Abbott Cc: Vlastimil Babka Cc: Wei Yang Cc: Yisheng Xie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/vmalloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 90520af7f186..937fe3acce86 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1440,7 +1440,7 @@ static void __vunmap(const void *addr, int deallocate_pages) addr)) return; - area = remove_vm_area(addr); + area = find_vmap_area((unsigned long)addr)->vm; if (unlikely(!area)) { WARN(1, KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr); @@ -1450,6 +1450,7 @@ static void __vunmap(const void *addr, int deallocate_pages) debug_check_no_locks_freed(addr, area->size); debug_check_no_obj_freed(addr, area->size); + remove_vm_area(addr); if (deallocate_pages) { int i; From 4148e331c422900f63a7bb7ec2474663311ce921 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Thu, 7 Jun 2018 17:05:17 -0700 Subject: [PATCH 143/392] mm/slub.c: add __printf verification to slab_err() [ Upstream commit a38965bf941b7c2af50de09c96bc5f03e136caef ] __printf is useful to verify format and arguments. Remove the following warning (with W=1): mm/slub.c:721:2: warning: function might be possible candidate for `gnu_printf' format attribute [-Wsuggest-attribute=format] Link: http://lkml.kernel.org/r/20180505200706.19986-1-malat@debian.org Signed-off-by: Mathieu Malaterre Reviewed-by: Andrew Morton Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/slub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/slub.c b/mm/slub.c index 332ce18463cb..70a9f027f963 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -636,7 +636,7 @@ static void object_err(struct kmem_cache *s, struct page *page, print_trailer(s, page, object); } -static void slab_err(struct kmem_cache *s, struct page *page, +static __printf(3, 4) void slab_err(struct kmem_cache *s, struct page *page, const char *fmt, ...) { va_list args; From bef7079cf332be466968d501998df5242ce3e058 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 5 Jun 2018 23:09:14 +0200 Subject: [PATCH 144/392] rtc: ensure rtc_set_alarm fails when alarms are not supported [ Upstream commit abfdff44bc38e9e2ef7929f633fb8462632299d4 ] When using RTC_ALM_SET or RTC_WKALM_SET with rtc_wkalrm.enabled not set, rtc_timer_enqueue() is not called and rtc_set_alarm() may succeed but the subsequent RTC_AIE_ON ioctl will fail. RTC_ALM_READ would also fail in that case. Ensure rtc_set_alarm() fails when alarms are not supported to avoid letting programs think the alarms are working for a particular RTC when they are not. Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/interface.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index d4153892c120..e0228294bff9 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -381,6 +381,11 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; + if (!rtc->ops) + return -ENODEV; + else if (!rtc->ops->set_alarm) + return -EINVAL; + err = rtc_valid_tm(&alarm->time); if (err != 0) return err; From 77e6abf43c95a39fd97a5fb644c26e303bd60459 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 1 Jun 2018 11:31:44 -0700 Subject: [PATCH 145/392] infiniband: fix a possible use-after-free bug [ Upstream commit cb2595c1393b4a5211534e6f0a0fbad369e21ad8 ] ucma_process_join() will free the new allocated "mc" struct, if there is any error after that, especially the copy_to_user(). But in parallel, ucma_leave_multicast() could find this "mc" through idr_find() before ucma_process_join() frees it, since it is already published. So "mc" could be used in ucma_leave_multicast() after it is been allocated and freed in ucma_process_join(), since we don't refcnt it. Fix this by separating "publish" from ID allocation, so that we can get an ID first and publish it later after copy_to_user(). Fixes: c8f6a362bf3e ("RDMA/cma: Add multicast communication support") Reported-by: Noam Rathaus Signed-off-by: Cong Wang Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 81dd84d0b68b..eaadd636c21b 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -180,7 +180,7 @@ static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx) return NULL; mutex_lock(&mut); - mc->id = idr_alloc(&multicast_idr, mc, 0, 0, GFP_KERNEL); + mc->id = idr_alloc(&multicast_idr, NULL, 0, 0, GFP_KERNEL); mutex_unlock(&mut); if (mc->id < 0) goto error; @@ -1262,6 +1262,10 @@ static ssize_t ucma_process_join(struct ucma_file *file, goto err3; } + mutex_lock(&mut); + idr_replace(&multicast_idr, mc, mc->id); + mutex_unlock(&mut); + mutex_unlock(&file->mut); ucma_put_ctx(ctx); return 0; From 7bae72078bff8f87173f4ce2543cbb35970af1e6 Mon Sep 17 00:00:00 2001 From: Stewart Smith Date: Thu, 29 Mar 2018 17:02:46 +1100 Subject: [PATCH 146/392] hvc_opal: don't set tb_ticks_per_usec in udbg_init_opal_common() [ Upstream commit 447808bf500a7cc92173266a59f8a494e132b122 ] time_init() will set up tb_ticks_per_usec based on reality. time_init() is called *after* udbg_init_opal_common() during boot. from arch/powerpc/kernel/time.c: unsigned long tb_ticks_per_usec = 100; /* sane default */ Currently, all powernv systems have a timebase frequency of 512mhz (512000000/1000000 == 0x200) - although there's nothing written down anywhere that I can find saying that we couldn't make that different based on the requirements in the ISA. So, we've been (accidentally) thwacking the (currently) correct (for powernv at least) value for tb_ticks_per_usec earlier than we otherwise would have. The "sane default" seems to be adequate for our purposes between udbg_init_opal_common() and time_init() being called, and if it isn't, then we should probably be setting it somewhere that isn't hvc_opal.c! Signed-off-by: Stewart Smith Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_opal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index a2cc5f834c63..ed18a98a15d8 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -337,7 +337,6 @@ static void udbg_init_opal_common(void) udbg_putc = udbg_opal_putc; udbg_getc = udbg_opal_getc; udbg_getc_poll = udbg_opal_getc_poll; - tb_ticks_per_usec = 0x200; /* Make udelay not suck */ } void __init hvc_opal_init_early(void) From b3ab448458ed69f6cb3c408c30d38e29acc06001 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 29 May 2018 14:56:19 +0300 Subject: [PATCH 147/392] RDMA/mad: Convert BUG_ONs to error flows [ Upstream commit 2468b82d69e3a53d024f28d79ba0fdb8bf43dfbf ] Let's perform checks in-place instead of BUG_ONs. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/mad.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 74c30f4c557e..0c79b0626a6e 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1466,7 +1466,8 @@ static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, mad_reg_req->oui, 3)) { method = &(*vendor_table)->vendor_class[ vclass]->method_table[i]; - BUG_ON(!*method); + if (!*method) + goto error3; goto check_in_use; } } @@ -1476,10 +1477,12 @@ static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, vclass]->oui[i])) { method = &(*vendor_table)->vendor_class[ vclass]->method_table[i]; - BUG_ON(*method); /* Allocate method table for this OUI */ - if ((ret = allocate_method_table(method))) - goto error3; + if (!*method) { + ret = allocate_method_table(method); + if (ret) + goto error3; + } memcpy((*vendor_table)->vendor_class[vclass]->oui[i], mad_reg_req->oui, 3); goto check_in_use; From 031e96b6ffde712a300b7697bc8375351eb8bccf Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Tue, 29 May 2018 16:13:03 -0600 Subject: [PATCH 148/392] usbip: usbip_detach: Fix memory, udev context and udev leak [ Upstream commit d179f99a651685b19333360e6558110da2fe9bd7 ] detach_port() fails to call usbip_vhci_driver_close() from its error path after usbip_vhci_detach_device() returns failure, leaking memory allocated in usbip_vhci_driver_open() and holding udev_context and udev references. Fix it to call usbip_vhci_driver_close(). Signed-off-by: Shuah Khan (Samsung OSG) Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/usb/usbip/src/usbip_detach.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/usb/usbip/src/usbip_detach.c b/tools/usb/usbip/src/usbip_detach.c index 05c6d15856eb..b4356ed875e5 100644 --- a/tools/usb/usbip/src/usbip_detach.c +++ b/tools/usb/usbip/src/usbip_detach.c @@ -43,7 +43,7 @@ void usbip_detach_usage(void) static int detach_port(char *port) { - int ret; + int ret = 0; uint8_t portnum; char path[PATH_MAX+1]; @@ -71,9 +71,12 @@ static int detach_port(char *port) } ret = usbip_vhci_detach_device(portnum); - if (ret < 0) - return -1; + if (ret < 0) { + ret = -1; + goto call_driver_close; + } +call_driver_close: usbip_vhci_driver_close(); return ret; From a461ae00464937f66812feae551c9e0526bce769 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Thu, 3 May 2018 11:25:08 -0700 Subject: [PATCH 149/392] perf/x86/intel/uncore: Correct fixed counter index check in generic code [ Upstream commit 4749f8196452eeb73cf2086a6a9705bae479d33d ] There is no index which is bigger than UNCORE_PMC_IDX_FIXED. The only exception is client IMC uncore, which has been specially handled. For generic code, it is not correct to use >= to check fixed counter. The code quality issue will bring problem when a new counter index is introduced. Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Cc: acme@kernel.org Cc: eranian@google.com Link: http://lkml.kernel.org/r/1525371913-10597-3-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index e98f68cfea02..cae9a3b6446b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -175,7 +175,7 @@ void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *e u64 prev_count, new_count, delta; int shift; - if (event->hw.idx >= UNCORE_PMC_IDX_FIXED) + if (event->hw.idx == UNCORE_PMC_IDX_FIXED) shift = 64 - uncore_fixed_ctr_bits(box); else shift = 64 - uncore_perf_ctr_bits(box); From c5061ffff5e9cad1fffba721546550af15dbda15 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Thu, 3 May 2018 11:25:07 -0700 Subject: [PATCH 150/392] perf/x86/intel/uncore: Correct fixed counter index check for NHM [ Upstream commit d71f11c076c420c4e2fceb4faefa144e055e0935 ] For Nehalem and Westmere, there is only one fixed counter for W-Box. There is no index which is bigger than UNCORE_PMC_IDX_FIXED. It is not correct to use >= to check fixed counter. The code quality issue will bring problem when new counter index is introduced. Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Cc: acme@kernel.org Cc: eranian@google.com Link: http://lkml.kernel.org/r/1525371913-10597-2-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c index 2749965afed0..83cadc2605a7 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c @@ -240,7 +240,7 @@ static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct p { struct hw_perf_event *hwc = &event->hw; - if (hwc->idx >= UNCORE_PMC_IDX_FIXED) + if (hwc->idx == UNCORE_PMC_IDX_FIXED) wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0); else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0) wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22); From a7bb99f521843297a25ec6c4eeba96dd80092a90 Mon Sep 17 00:00:00 2001 From: Kai Chieh Chuang Date: Mon, 28 May 2018 10:18:18 +0800 Subject: [PATCH 151/392] ASoC: dpcm: fix BE dai not hw_free and shutdown [ Upstream commit 9c0ac70ad24d76b873c1551e27790c7f6a815d5c ] In case, one BE is used by two FE1/FE2 FE1--->BE--> | FE2----] when FE1/FE2 call dpcm_be_dai_hw_free() together the BE users will be 2 (> 1), hence cannot be hw_free the be state will leave at, ex. SND_SOC_DPCM_STATE_STOP later FE1/FE2 call dpcm_be_dai_shutdown(), will be skip due to wrong state. leaving the BE not being hw_free and shutdown. The BE dai will be hw_free later when calling dpcm_be_dai_shutdown() if still in invalid state. Signed-off-by: KaiChieh Chuang Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/soc-pcm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 2ee3b9dbe4f4..e2fb859fbbaa 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1611,8 +1611,10 @@ int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) continue; if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) - continue; + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) { + soc_pcm_hw_free(be_substream); + be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; + } dev_dbg(be->dev, "ASoC: close BE %s\n", dpcm->fe->dai_link->name); From cb0d96f440671ac822e5301e64adea817276d18b Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Thu, 24 May 2018 19:18:27 +0530 Subject: [PATCH 152/392] mwifiex: handle race during mwifiex_usb_disconnect [ Upstream commit b817047ae70c0bd67b677b65d0d69d72cd6e9728 ] Race condition is observed during rmmod of mwifiex_usb: 1. The rmmod thread will call mwifiex_usb_disconnect(), download SHUTDOWN command and do wait_event_interruptible_timeout(), waiting for response. 2. The main thread will handle the response and will do a wake_up_interruptible(), unblocking rmmod thread. 3. On getting unblocked, rmmod thread will make rx_cmd.urb = NULL in mwifiex_usb_free(). 4. The main thread will try to resubmit rx_cmd.urb in mwifiex_usb_submit_rx_urb(), which is NULL. To fix, wait for main thread to complete before calling mwifiex_usb_free(). Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mwifiex/usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 4371e12b36f3..3f239f1ad203 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -556,6 +556,9 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) MWIFIEX_FUNC_SHUTDOWN); } + if (adapter->workqueue) + flush_workqueue(adapter->workqueue); + mwifiex_usb_free(card); dev_dbg(adapter->dev, "%s: removing card\n", __func__); From 8362d3e90c1105380b4b2b1bd232a638e3f3f807 Mon Sep 17 00:00:00 2001 From: Eyal Reizer Date: Mon, 28 May 2018 11:36:42 +0300 Subject: [PATCH 153/392] wlcore: sdio: check for valid platform device data before suspend [ Upstream commit 6e91d48371e79862ea2c05867aaebe4afe55a865 ] the wl pointer can be null In case only wlcore_sdio is probed while no WiLink module is successfully probed, as in the case of mounting a wl12xx module while using a device tree file configured with wl18xx related settings. In this case the system was crashing in wl1271_suspend() as platform device data is not set. Make sure wl the pointer is valid before using it. Signed-off-by: Eyal Reizer Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ti/wlcore/sdio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index d3dd7bfdf3f1..63b55b2261e5 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -342,6 +342,11 @@ static int wl1271_suspend(struct device *dev) mmc_pm_flag_t sdio_flags; int ret = 0; + if (!wl) { + dev_err(dev, "no wilink module was probed\n"); + goto out; + } + dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", wl->wow_enabled); From 0bedc117bab4a0ac92de0e856e896e1f708f1c57 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 18 May 2018 18:56:24 +0200 Subject: [PATCH 154/392] PCI: Prevent sysfs disable of device while driver is attached [ Upstream commit 6f5cdfa802733dcb561bf664cc89d203f2fd958f ] Manipulating the enable_cnt behind the back of the driver will wreak complete havoc with the kernel state, so disallow it. Signed-off-by: Christoph Hellwig Signed-off-by: Bjorn Helgaas Reviewed-by: Johannes Thumshirn Acked-by: Keith Busch Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-sysfs.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 318707870cb2..6b66f9950b57 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -199,13 +199,16 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!val) { - if (pci_is_enabled(pdev)) - pci_disable_device(pdev); - else - result = -EIO; - } else + device_lock(dev); + if (dev->driver) + result = -EBUSY; + else if (val) result = pci_enable_device(pdev); + else if (pci_is_enabled(pdev)) + pci_disable_device(pdev); + else + result = -EIO; + device_unlock(dev); return result < 0 ? result : count; } From d3fbe970e457ab5382615644b205a0adc1fb19e5 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:30 +0300 Subject: [PATCH 155/392] ath: Add regulatory mapping for FCC3_ETSIC [ Upstream commit 01fb2994a98dc72c8818c274f7b5983d5dd885c7 ] The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index bdd2b4d61f2f..7d955fa8c24c 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -35,6 +35,7 @@ enum EnumRd { FRANCE_RES = 0x31, FCC3_FCCA = 0x3A, FCC3_WORLD = 0x3B, + FCC3_ETSIC = 0x3F, ETSI1_WORLD = 0x37, ETSI3_ETSIA = 0x32, @@ -168,6 +169,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, {FCC3_FCCA, CTL_FCC, CTL_FCC}, {FCC3_WORLD, CTL_FCC, CTL_ETSI}, + {FCC3_ETSIC, CTL_FCC, CTL_ETSI}, {FCC4_FCCA, CTL_FCC, CTL_FCC}, {FCC5_FCCA, CTL_FCC, CTL_FCC}, {FCC6_FCCA, CTL_FCC, CTL_FCC}, From 31d83e727318298c83847a12f895e358b24da462 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:18 +0300 Subject: [PATCH 156/392] ath: Add regulatory mapping for ETSI8_WORLD [ Upstream commit 45faf6e096da8bb80e1ddf8c08a26a9601d9469e ] The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 7d955fa8c24c..7c0fcbbf1900 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -45,6 +45,7 @@ enum EnumRd { ETSI4_ETSIC = 0x38, ETSI5_WORLD = 0x39, ETSI6_WORLD = 0x34, + ETSI8_WORLD = 0x3D, ETSI_RESERVED = 0x33, MKK1_MKKA = 0x40, @@ -181,6 +182,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {ETSI4_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI5_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI6_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI8_WORLD, CTL_ETSI, CTL_ETSI}, /* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */ {ETSI3_ETSIA, CTL_ETSI, CTL_ETSI}, From 55d4979643b1e4c0a53de84924ba5a95c5ab67f6 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:14 +0300 Subject: [PATCH 157/392] ath: Add regulatory mapping for APL13_WORLD [ Upstream commit 9ba8df0c52b3e6baa436374b429d3d73bd09a320 ] The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 7c0fcbbf1900..2c873840a46a 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -69,6 +69,7 @@ enum EnumRd { APL1_ETSIC = 0x55, APL2_ETSIC = 0x56, APL5_WORLD = 0x58, + APL13_WORLD = 0x5A, APL6_WORLD = 0x5B, APL7_FCCA = 0x5C, APL8_WORLD = 0x5D, @@ -195,6 +196,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {APL3_WORLD, CTL_FCC, CTL_ETSI}, {APL4_WORLD, CTL_FCC, CTL_ETSI}, {APL5_WORLD, CTL_FCC, CTL_ETSI}, + {APL13_WORLD, CTL_ETSI, CTL_ETSI}, {APL6_WORLD, CTL_ETSI, CTL_ETSI}, {APL8_WORLD, CTL_ETSI, CTL_ETSI}, {APL9_WORLD, CTL_ETSI, CTL_ETSI}, From 396b5e67999be8537924c22e5d6eeaa89e585152 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:05 +0300 Subject: [PATCH 158/392] ath: Add regulatory mapping for APL2_FCCA [ Upstream commit 4f183687e3fad3ce0e06e38976cad81bc4541990 ] The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: FCC * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 2c873840a46a..d8a7db4976f0 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -61,6 +61,7 @@ enum EnumRd { MKK1_MKKA1 = 0x4A, MKK1_MKKA2 = 0x4B, MKK1_MKKC = 0x4C, + APL2_FCCA = 0x4D, APL3_FCCA = 0x50, APL1_WORLD = 0x52, @@ -193,6 +194,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {FCC1_FCCA, CTL_FCC, CTL_FCC}, {APL1_WORLD, CTL_FCC, CTL_ETSI}, {APL2_WORLD, CTL_FCC, CTL_ETSI}, + {APL2_FCCA, CTL_FCC, CTL_FCC}, {APL3_WORLD, CTL_FCC, CTL_ETSI}, {APL4_WORLD, CTL_FCC, CTL_ETSI}, {APL5_WORLD, CTL_FCC, CTL_ETSI}, From f0589b82d272b183225b6a8cd8c9f78359e6ca65 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:54 +0300 Subject: [PATCH 159/392] ath: Add regulatory mapping for Uganda [ Upstream commit 1ea3986ad2bc72081c69f3fbc1e5e0eeb3c44f17 ] The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 37f53bd8fcb1..18a4d0557f18 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -175,6 +175,7 @@ enum CountryCode { CTRY_TUNISIA = 788, CTRY_TURKEY = 792, CTRY_UAE = 784, + CTRY_UGANDA = 800, CTRY_UKRAINE = 804, CTRY_UNITED_KINGDOM = 826, CTRY_UNITED_STATES = 840, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index d8a7db4976f0..cba1020bc854 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -467,6 +467,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, {CTRY_TURKEY, ETSI3_WORLD, "TR"}, + {CTRY_UGANDA, FCC3_WORLD, "UG"}, {CTRY_UKRAINE, NULL1_WORLD, "UA"}, {CTRY_UAE, NULL1_WORLD, "AE"}, {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, From 4b2c7cf52e4bead28ada187cf9617af442b4d00a Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:48 +0300 Subject: [PATCH 160/392] ath: Add regulatory mapping for Tanzania [ Upstream commit 667ddac5745fb9fddfe8f7fd2523070f50bd4442 ] The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 18a4d0557f18..7439e62f5262 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -170,6 +170,7 @@ enum CountryCode { CTRY_SWITZERLAND = 756, CTRY_SYRIA = 760, CTRY_TAIWAN = 158, + CTRY_TANZANIA = 834, CTRY_THAILAND = 764, CTRY_TRINIDAD_Y_TOBAGO = 780, CTRY_TUNISIA = 788, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index cba1020bc854..b85dc86cc188 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -463,6 +463,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, {CTRY_SYRIA, NULL1_WORLD, "SY"}, {CTRY_TAIWAN, APL3_FCCA, "TW"}, + {CTRY_TANZANIA, APL1_WORLD, "TZ"}, {CTRY_THAILAND, FCC3_WORLD, "TH"}, {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, From bbd7480ed12baae07655de385075bc496f5f68bb Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:43 +0300 Subject: [PATCH 161/392] ath: Add regulatory mapping for Serbia [ Upstream commit 2a3169a54bb53717928392a04fb84deb765b51f1 ] The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 7439e62f5262..a0ed5f8b554e 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -159,6 +159,7 @@ enum CountryCode { CTRY_ROMANIA = 642, CTRY_RUSSIA = 643, CTRY_SAUDI_ARABIA = 682, + CTRY_SERBIA = 688, CTRY_SERBIA_MONTENEGRO = 891, CTRY_SINGAPORE = 702, CTRY_SLOVAKIA = 703, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index b85dc86cc188..1ced5a323cf8 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -452,6 +452,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_ROMANIA, NULL1_WORLD, "RO"}, {CTRY_RUSSIA, NULL1_WORLD, "RU"}, {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, + {CTRY_SERBIA, ETSI1_WORLD, "RS"}, {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, {CTRY_SINGAPORE, APL6_WORLD, "SG"}, {CTRY_SLOVAKIA, ETSI1_WORLD, "SK"}, From 6c40849333bd44ef96068bebe226cb5d3531ad2a Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:09:59 +0300 Subject: [PATCH 162/392] ath: Add regulatory mapping for Bermuda [ Upstream commit 9c790f2d234f65697e3b0948adbfdf36dbe63dd7 ] The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: FCC * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index a0ed5f8b554e..a9334d514154 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -74,6 +74,7 @@ enum CountryCode { CTRY_BELARUS = 112, CTRY_BELGIUM = 56, CTRY_BELIZE = 84, + CTRY_BERMUDA = 60, CTRY_BOLIVIA = 68, CTRY_BOSNIA_HERZ = 70, CTRY_BRAZIL = 76, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 1ced5a323cf8..e13b96e45d53 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -313,6 +313,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, {CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, {CTRY_BELIZE, APL1_ETSIC, "BZ"}, + {CTRY_BERMUDA, FCC3_FCCA, "BM"}, {CTRY_BOLIVIA, APL1_ETSIC, "BO"}, {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, {CTRY_BRAZIL, FCC3_WORLD, "BR"}, From 84e90658ed8d5dbc8701d76b491206208cbeb86b Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:09:53 +0300 Subject: [PATCH 163/392] ath: Add regulatory mapping for Bahamas [ Upstream commit 699e2302c286a14afe7b7394151ce6c4e1790cc1 ] The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index a9334d514154..184b6810cde9 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -68,6 +68,7 @@ enum CountryCode { CTRY_AUSTRALIA = 36, CTRY_AUSTRIA = 40, CTRY_AZERBAIJAN = 31, + CTRY_BAHAMAS = 44, CTRY_BAHRAIN = 48, CTRY_BANGLADESH = 50, CTRY_BARBADOS = 52, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index e13b96e45d53..15bbd1e0d912 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -306,6 +306,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, + {CTRY_BAHAMAS, FCC3_WORLD, "BS"}, {CTRY_BAHRAIN, APL6_WORLD, "BH"}, {CTRY_BANGLADESH, NULL1_WORLD, "BD"}, {CTRY_BARBADOS, FCC2_WORLD, "BB"}, From a4b3eaf0bb6f753e10ab7b19acb77844a8b4b78c Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Thu, 22 Mar 2018 21:20:03 +0100 Subject: [PATCH 164/392] powerpc/32: Add a missing include header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit c89ca593220931c150cffda24b4d4ccf82f13fc8 ] The header file was missing from the includes. Fix the following warning, treated as error with W=1: arch/powerpc/kernel/pci_32.c:286:6: error: no previous prototype for ‘sys_pciconfig_iobase’ [-Werror=missing-prototypes] Signed-off-by: Mathieu Malaterre Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/pci_32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 432459c817fa..28724443d1a6 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include From 6d5f93d2f252c9d3e69fdac3ded39cd8c112acfe Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Thu, 22 Mar 2018 21:19:56 +0100 Subject: [PATCH 165/392] powerpc/chrp/time: Make some functions static, add missing header include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit b87a358b4a1421abd544c0b554b1b7159b2b36c0 ] Add a missing include . These functions can all be static, make it so. Fix warnings treated as errors with W=1: arch/powerpc/platforms/chrp/time.c:41:13: error: no previous prototype for ‘chrp_time_init’ [-Werror=missing-prototypes] arch/powerpc/platforms/chrp/time.c:66:5: error: no previous prototype for ‘chrp_cmos_clock_read’ [-Werror=missing-prototypes] arch/powerpc/platforms/chrp/time.c:74:6: error: no previous prototype for ‘chrp_cmos_clock_write’ [-Werror=missing-prototypes] arch/powerpc/platforms/chrp/time.c:86:5: error: no previous prototype for ‘chrp_set_rtc_time’ [-Werror=missing-prototypes] arch/powerpc/platforms/chrp/time.c:130:6: error: no previous prototype for ‘chrp_get_rtc_time’ [-Werror=missing-prototypes] Signed-off-by: Mathieu Malaterre Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/chrp/time.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c index f803f4b8ab6f..8608e358217f 100644 --- a/arch/powerpc/platforms/chrp/time.c +++ b/arch/powerpc/platforms/chrp/time.c @@ -27,6 +27,8 @@ #include #include +#include + extern spinlock_t rtc_lock; #define NVRAM_AS0 0x74 @@ -62,7 +64,7 @@ long __init chrp_time_init(void) return 0; } -int chrp_cmos_clock_read(int addr) +static int chrp_cmos_clock_read(int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); @@ -70,7 +72,7 @@ int chrp_cmos_clock_read(int addr) return (inb(nvram_data)); } -void chrp_cmos_clock_write(unsigned long val, int addr) +static void chrp_cmos_clock_write(unsigned long val, int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); From 12a9b5fc3130284c3fa667f577858ef4a5ba647e Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 4 Apr 2018 22:13:05 +0200 Subject: [PATCH 166/392] powerpc/powermac: Add missing prototype for note_bootable_part() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f72cf3f1d49f2c35d6cb682af2e8c93550f264e4 ] Add a missing prototype for function `note_bootable_part` to silence a warning treated as error with W=1: arch/powerpc/platforms/powermac/setup.c:361:12: error: no previous prototype for ‘note_bootable_part’ [-Werror=missing-prototypes] Suggested-by: Christophe Leroy Signed-off-by: Mathieu Malaterre Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powermac/setup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index b127a29ac526..49148e2e13a8 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -359,6 +359,7 @@ static int pmac_late_init(void) } machine_late_initcall(powermac, pmac_late_init); +void note_bootable_part(dev_t dev, int part, int goodness); /* * This is __init_refok because we check for "initializing" before * touching any of the __init sensitive things and "initializing" From 9261dfa009fcf768057b68484afb9a48e624632c Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 4 Apr 2018 22:07:46 +0200 Subject: [PATCH 167/392] powerpc/powermac: Mark variable x as unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 5a4b475cf8511da721f20ba432c244061db7139f ] Since the value of x is never intended to be read, declare it with gcc attribute as unused. Fix warning treated as error with W=1: arch/powerpc/platforms/powermac/bootx_init.c:471:21: error: variable ‘x’ set but not used [-Werror=unused-but-set-variable] Suggested-by: Christophe Leroy Signed-off-by: Mathieu Malaterre Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powermac/bootx_init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index 3e91ef538114..9adc9eaaf365 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -467,7 +467,7 @@ void __init bootx_init(unsigned long r3, unsigned long r4) boot_infos_t *bi = (boot_infos_t *) r4; unsigned long hdr; unsigned long space; - unsigned long ptr, x; + unsigned long ptr; char *model; unsigned long offset = reloc_offset(); @@ -561,6 +561,8 @@ void __init bootx_init(unsigned long r3, unsigned long r4) * MMU switched OFF, so this should not be useful anymore. */ if (bi->version < 4) { + unsigned long x __maybe_unused; + bootx_printf("Touching pages...\n"); /* From 723139e8e04ece9b299379db50e3b598d10177a1 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 24 May 2018 11:02:06 +0000 Subject: [PATCH 168/392] powerpc/8xx: fix invalid register expression in head_8xx.S [ Upstream commit e4ccb1dae6bdef228d729c076c38161ef6e7ca34 ] New binutils generate the following warning AS arch/powerpc/kernel/head_8xx.o arch/powerpc/kernel/head_8xx.S: Assembler messages: arch/powerpc/kernel/head_8xx.S:916: Warning: invalid register expression This patch fixes it. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/head_8xx.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index fafff8dbd5d9..3c957548f336 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -722,7 +722,7 @@ start_here: tovirt(r6,r6) lis r5, abatron_pteptrs@h ori r5, r5, abatron_pteptrs@l - stw r5, 0xf0(r0) /* Must match your Abatron config file */ + stw r5, 0xf0(0) /* Must match your Abatron config file */ tophys(r5,r5) stw r6, 0(r5) From 6af19d06df562a5393e8d5a2c6d5b7739caf313e Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 23 May 2018 17:19:22 -0500 Subject: [PATCH 169/392] PCI: pciehp: Request control of native hotplug only if supported [ Upstream commit 408fec36a1ab3d14273c2116b449ef1e9be3cb8b ] Currently we request control of native PCIe hotplug unconditionally. Native PCIe hotplug events are handled by the pciehp driver, and if it is not enabled those events will be lost. Request control of native PCIe hotplug only if the pciehp driver is enabled, so we will actually handle native PCIe hotplug events. Suggested-by: Bjorn Helgaas Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/pci_root.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index cd4de7e038ea..3e72f9b42097 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -476,9 +476,11 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, } control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL - | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | OSC_PCI_EXPRESS_PME_CONTROL; + if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) + control |= OSC_PCI_EXPRESS_NATIVE_HP_CONTROL; + if (pci_aer_available()) { if (aer_acpi_firmware_first()) dev_info(&device->dev, From c656aaac05092baa90e4fd37fc4bbe684c2d40d1 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 3 May 2018 16:37:16 +0530 Subject: [PATCH 170/392] scsi: ufs: fix exception event handling [ Upstream commit 2e3611e9546c2ed4def152a51dfd34e8dddae7a5 ] The device can set the exception event bit in one of the response UPIU, for example to notify the need for urgent BKOPs operation. In such a case, the host driver calls ufshcd_exception_event_handler to handle this notification. When trying to check the exception event status (for finding the cause for the exception event), the device may be busy with additional SCSI commands handling and may not respond within the 100ms timeout. To prevent that, we need to block SCSI commands during handling of exception events and allow retransmissions of the query requests, in case of timeout. Signed-off-by: Subhash Jadavani Signed-off-by: Maya Erez Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ufs/ufshcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d5fbf2e228f9..39a4e61bf8d2 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3330,6 +3330,7 @@ static void ufshcd_exception_event_handler(struct work_struct *work) hba = container_of(work, struct ufs_hba, eeh_work); pm_runtime_get_sync(hba->dev); + scsi_block_requests(hba->host); err = ufshcd_get_ee_status(hba, &status); if (err) { dev_err(hba->dev, "%s: failed to get exception status %d\n", @@ -3345,6 +3346,7 @@ static void ufshcd_exception_event_handler(struct work_struct *work) __func__, err); } out: + scsi_unblock_requests(hba->host); pm_runtime_put_sync(hba->dev); return; } From ee9460d400aca613555368532dd304d49fd7764b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 17 May 2018 20:02:23 +0200 Subject: [PATCH 171/392] ALSA: emu10k1: Rate-limit error messages about page errors [ Upstream commit 11d42c81036324697d367600bfc16f6dd37636fd ] The error messages at sanity checks of memory pages tend to repeat too many times once when it hits, and without the rate limit, it may flood and become unreadable. Replace such messages with the *_ratelimited() variant. Bugzilla: http://bugzilla.opensuse.org/show_bug.cgi?id=1093027 Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/pci/emu10k1/memory.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 4f1f69be1865..8c778fa33031 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -237,13 +237,13 @@ search_empty(struct snd_emu10k1 *emu, int size) static int is_valid_page(struct snd_emu10k1 *emu, dma_addr_t addr) { if (addr & ~emu->dma_mask) { - dev_err(emu->card->dev, + dev_err_ratelimited(emu->card->dev, "max memory size is 0x%lx (addr = 0x%lx)!!\n", emu->dma_mask, (unsigned long)addr); return 0; } if (addr & (EMUPAGESIZE-1)) { - dev_err(emu->card->dev, "page is not aligned\n"); + dev_err_ratelimited(emu->card->dev, "page is not aligned\n"); return 0; } return 1; @@ -334,7 +334,7 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst else addr = snd_pcm_sgbuf_get_addr(substream, ofs); if (! is_valid_page(emu, addr)) { - dev_err(emu->card->dev, + dev_err_ratelimited(emu->card->dev, "emu: failure page = %d\n", idx); mutex_unlock(&hdr->block_mutex); return NULL; From ac34de0dff6a408595bf34c1b1f8be37681ce682 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 17 May 2018 15:27:22 +0800 Subject: [PATCH 172/392] regulator: pfuze100: add .is_enable() for pfuze100_swb_regulator_ops [ Upstream commit 0b01fd3d40fe6402e5fa3b491ef23109feb1aaa5 ] If is_enabled() is not defined, regulator core will assume this regulator is already enabled, then it can NOT be really enabled after disabled. Based on Li Jun's patch from the NXP kernel tree. Signed-off-by: Anson Huang Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/regulator/pfuze100-regulator.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index c879dff597ee..eceb75105c08 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -142,6 +142,7 @@ static struct regulator_ops pfuze100_sw_regulator_ops = { static struct regulator_ops pfuze100_swb_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, From 85733056dbf8a32e1af4fc47e17882fd10f20dfe Mon Sep 17 00:00:00 2001 From: Yufen Yu Date: Fri, 4 May 2018 18:08:10 +0800 Subject: [PATCH 173/392] md: fix NULL dereference of mddev->pers in remove_and_add_spares() [ Upstream commit c42a0e2675721e1444f56e6132a07b7b1ec169ac ] We met NULL pointer BUG as follow: [ 151.760358] BUG: unable to handle kernel NULL pointer dereference at 0000000000000060 [ 151.761340] PGD 80000001011eb067 P4D 80000001011eb067 PUD 1011ea067 PMD 0 [ 151.762039] Oops: 0000 [#1] SMP PTI [ 151.762406] Modules linked in: [ 151.762723] CPU: 2 PID: 3561 Comm: mdadm-test Kdump: loaded Not tainted 4.17.0-rc1+ #238 [ 151.763542] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1.fc26 04/01/2014 [ 151.764432] RIP: 0010:remove_and_add_spares.part.56+0x13c/0x3a0 [ 151.765061] RSP: 0018:ffffc90001d7fcd8 EFLAGS: 00010246 [ 151.765590] RAX: 0000000000000000 RBX: ffff88013601d600 RCX: 0000000000000000 [ 151.766306] RDX: 0000000000000000 RSI: ffff88013601d600 RDI: ffff880136187000 [ 151.767014] RBP: ffff880136187018 R08: 0000000000000003 R09: 0000000000000051 [ 151.767728] R10: ffffc90001d7fed8 R11: 0000000000000000 R12: ffff88013601d600 [ 151.768447] R13: ffff8801298b1300 R14: ffff880136187000 R15: 0000000000000000 [ 151.769160] FS: 00007f2624276700(0000) GS:ffff88013ae80000(0000) knlGS:0000000000000000 [ 151.769971] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 151.770554] CR2: 0000000000000060 CR3: 0000000111aac000 CR4: 00000000000006e0 [ 151.771272] Call Trace: [ 151.771542] md_ioctl+0x1df2/0x1e10 [ 151.771906] ? __switch_to+0x129/0x440 [ 151.772295] ? __schedule+0x244/0x850 [ 151.772672] blkdev_ioctl+0x4bd/0x970 [ 151.773048] block_ioctl+0x39/0x40 [ 151.773402] do_vfs_ioctl+0xa4/0x610 [ 151.773770] ? dput.part.23+0x87/0x100 [ 151.774151] ksys_ioctl+0x70/0x80 [ 151.774493] __x64_sys_ioctl+0x16/0x20 [ 151.774877] do_syscall_64+0x5b/0x180 [ 151.775258] entry_SYSCALL_64_after_hwframe+0x44/0xa9 For raid6, when two disk of the array are offline, two spare disks can be added into the array. Before spare disks recovery completing, system reboot and mdadm thinks it is ok to restart the degraded array by md_ioctl(). Since disks in raid6 is not only_parity(), raid5_run() will abort, when there is no PPL feature or not setting 'start_dirty_degraded' parameter. Therefore, mddev->pers is NULL. But, mddev->raid_disks has been set and it will not be cleared when raid5_run abort. md_ioctl() can execute cmd 'HOT_REMOVE_DISK' to remove a disk by mdadm, which will cause NULL pointer dereference in remove_and_add_spares() finally. Signed-off-by: Yufen Yu Signed-off-by: Shaohua Li Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index f88f912f0296..ba201db6afce 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5676,6 +5676,9 @@ static int hot_remove_disk(struct mddev *mddev, dev_t dev) char b[BDEVNAME_SIZE]; struct md_rdev *rdev; + if (!mddev->pers) + return -ENODEV; + rdev = find_rdev(mddev, dev); if (!rdev) return -ENXIO; From 55d1f04913219fc98e6cc2a02aa29ac6eed718cc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 25 Apr 2018 11:04:21 -0400 Subject: [PATCH 174/392] media: smiapp: fix timeout checking in smiapp_read_nvm [ Upstream commit 7a2148dfda8001c983f0effd9afd8a7fa58e99c4 ] The current code decrements the timeout counter i and the end of each loop i is incremented, so the check for timeout will always be false and hence the timeout mechanism is just a dead code path. Potentially, if the RD_READY bit is not set, we could end up in an infinite loop. Fix this so the timeout starts from 1000 and decrements to zero, if at the end of the loop i is zero we have a timeout condition. Detected by CoverityScan, CID#1324008 ("Logically dead code") Fixes: ccfc97bdb5ae ("[media] smiapp: Add driver") Signed-off-by: Colin Ian King Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/smiapp/smiapp-core.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index b49254e4ea0a..6a2f204b902f 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -939,7 +939,7 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor, if (rval) goto out; - for (i = 0; i < 1000; i++) { + for (i = 1000; i > 0; i--) { rval = smiapp_read( sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s); @@ -950,11 +950,10 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor, if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY) break; - if (--i == 0) { - rval = -ETIMEDOUT; - goto out; - } - + } + if (!i) { + rval = -ETIMEDOUT; + goto out; } for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) { From ee7b57a2099fcde6cef65c6086acf3e42e400be0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 May 2018 20:07:18 +0200 Subject: [PATCH 175/392] ALSA: usb-audio: Apply rate limit to warning messages in URB complete callback [ Upstream commit 377a879d9832f4ba69bd6a1fc996bb4181b1e504 ] retire_capture_urb() may print warning messages when the given URB doesn't align, and this may flood the system log easily. Put the rate limit to the message for avoiding it. Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1093485 Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/usb/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 0d8aba5fe1a8..946f89883ae0 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1263,7 +1263,7 @@ static void retire_capture_urb(struct snd_usb_substream *subs, if (bytes % (runtime->sample_bits >> 3) != 0) { int oldbytes = bytes; bytes = frames * stride; - dev_warn(&subs->dev->dev, + dev_warn_ratelimited(&subs->dev->dev, "Corrected urb data len. %d->%d\n", oldbytes, bytes); } From c70d92d28f5537ae15464781a5fdb13f329458f6 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Tue, 24 Apr 2018 15:15:13 +0200 Subject: [PATCH 176/392] drm/radeon: fix mode_valid's return type [ Upstream commit 7a47f20eb1fb8fa8d7a8fe3a4fd8c721f04c2174 ] The method struct drm_connector_helper_funcs::mode_valid is defined as returning an 'enum drm_mode_status' but the driver implementation for this method uses an 'int' for it. Fix this by using 'enum drm_mode_status' in the driver too. Signed-off-by: Luc Van Oostenryck Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 4f686bb6bad7..7c032d652c44 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -804,7 +804,7 @@ static int radeon_lvds_get_modes(struct drm_connector *connector) return ret; } -static int radeon_lvds_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = radeon_best_single_encoder(connector); @@ -947,7 +947,7 @@ static int radeon_vga_get_modes(struct drm_connector *connector) return ret; } -static int radeon_vga_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_vga_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; @@ -1086,7 +1086,7 @@ static int radeon_tv_get_modes(struct drm_connector *connector) return 1; } -static int radeon_tv_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { if ((mode->hdisplay > 1024) || (mode->vdisplay > 768)) @@ -1387,7 +1387,7 @@ static void radeon_dvi_force(struct drm_connector *connector) radeon_connector->use_digital = true; } -static int radeon_dvi_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_dvi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; @@ -1666,7 +1666,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force) return ret; } -static int radeon_dp_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; From 1a9b0f0830e384f699644465912ad36657f34e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Thu, 10 May 2018 23:59:19 +0200 Subject: [PATCH 177/392] powerpc/embedded6xx/hlwd-pic: Prevent interrupts from being handled by Starlet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9dcb3df4281876731e4e8bff7940514d72375154 ] The interrupt controller inside the Wii's Hollywood chip is connected to two masters, the "Broadway" PowerPC and the "Starlet" ARM926, each with their own interrupt status and mask registers. When booting the Wii with mini[1], interrupts from the SD card controller (IRQ 7) are handled by the ARM, because mini provides SD access over IPC. Linux however can't currently use or disable this IPC service, so both sides try to handle IRQ 7 without coordination. Let's instead make sure that all interrupts that are unmasked on the PPC side are masked on the ARM side; this will also make sure that Linux can properly talk to the SD card controller (and potentially other devices). If access to a device through IPC is desired in the future, interrupts from that device should not be handled by Linux directly. [1]: https://github.com/lewurm/mini Signed-off-by: Jonathan Neuschäfer Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/embedded6xx/hlwd-pic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index c269caee58f9..f44b382449ca 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -35,6 +35,8 @@ */ #define HW_BROADWAY_ICR 0x00 #define HW_BROADWAY_IMR 0x04 +#define HW_STARLET_ICR 0x08 +#define HW_STARLET_IMR 0x0c /* @@ -74,6 +76,9 @@ static void hlwd_pic_unmask(struct irq_data *d) void __iomem *io_base = irq_data_get_irq_chip_data(d); setbits32(io_base + HW_BROADWAY_IMR, 1 << irq); + + /* Make sure the ARM (aka. Starlet) doesn't handle this interrupt. */ + clrbits32(io_base + HW_STARLET_IMR, 1 << irq); } From ad4d00d20c69c9f3a39edfde22b279810aaf3c8c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 9 May 2018 12:12:15 -0700 Subject: [PATCH 178/392] HID: i2c-hid: check if device is there before really probing [ Upstream commit b3a81b6c4fc6730ac49e20d789a93c0faabafc98 ] On many Chromebooks touch devices are multi-sourced; the components are electrically compatible and one can be freely swapped for another without changing the OS image or firmware. To avoid bunch of scary messages when device is not actually present in the system let's try testing basic communication with it and if there is no response terminate probe early with -ENXIO. Signed-off-by: Dmitry Torokhov Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hid/i2c-hid/i2c-hid.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 2d86ac02b2cd..8463f83e037f 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -981,6 +981,14 @@ static int i2c_hid_probe(struct i2c_client *client, pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); + /* Make sure there is something at this address */ + ret = i2c_smbus_read_byte(client); + if (ret < 0) { + dev_dbg(&client->dev, "nothing at this address: %d\n", ret); + ret = -ENXIO; + goto err_pm; + } + ret = i2c_hid_fetch_hid_descriptor(ihid); if (ret < 0) goto err_pm; From 6d9cd12792270773fab9e5a129daff328d61ef9e Mon Sep 17 00:00:00 2001 From: DaeRyong Jeong Date: Tue, 1 May 2018 00:27:04 +0900 Subject: [PATCH 179/392] tty: Fix data race in tty_insert_flip_string_fixed_flag [ Upstream commit b6da31b2c07c46f2dcad1d86caa835227a16d9ff ] Unlike normal serials, in pty layer, there is no guarantee that multiple threads don't insert input characters at the same time. If it is happened, tty_insert_flip_string_fixed_flag can be executed concurrently. This can lead slab out-of-bounds write in tty_insert_flip_string_fixed_flag. Call sequences are as follows. CPU0 CPU1 n_tty_ioctl_helper n_tty_ioctl_helper __start_tty tty_send_xchar tty_wakeup pty_write n_hdlc_tty_wakeup tty_insert_flip_string n_hdlc_send_frames tty_insert_flip_string_fixed_flag pty_write tty_insert_flip_string tty_insert_flip_string_fixed_flag To fix the race, acquire port->lock in pty_write() before it inserts input characters to tty buffer. It prevents multiple threads from inserting input characters concurrently. The crash log is as follows: BUG: KASAN: slab-out-of-bounds in tty_insert_flip_string_fixed_flag+0xb5/ 0x130 drivers/tty/tty_buffer.c:316 at addr ffff880114fcc121 Write of size 1792 by task syz-executor0/30017 CPU: 1 PID: 30017 Comm: syz-executor0 Not tainted 4.8.0 #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.8.2-0-g33fbe13 by qemu-project.org 04/01/2014 0000000000000000 ffff88011638f888 ffffffff81694cc3 ffff88007d802140 ffff880114fcb300 ffff880114fcc300 ffff880114fcb300 ffff88011638f8b0 ffffffff8130075c ffff88011638f940 ffff88007d802140 ffff880194fcc121 Call Trace: __dump_stack lib/dump_stack.c:15 [inline] dump_stack+0xb3/0x110 lib/dump_stack.c:51 kasan_object_err+0x1c/0x70 mm/kasan/report.c:156 print_address_description mm/kasan/report.c:194 [inline] kasan_report_error+0x1f7/0x4e0 mm/kasan/report.c:283 kasan_report+0x36/0x40 mm/kasan/report.c:303 check_memory_region_inline mm/kasan/kasan.c:292 [inline] check_memory_region+0x13e/0x1a0 mm/kasan/kasan.c:299 memcpy+0x37/0x50 mm/kasan/kasan.c:335 tty_insert_flip_string_fixed_flag+0xb5/0x130 drivers/tty/tty_buffer.c:316 tty_insert_flip_string include/linux/tty_flip.h:35 [inline] pty_write+0x7f/0xc0 drivers/tty/pty.c:115 n_hdlc_send_frames+0x1d4/0x3b0 drivers/tty/n_hdlc.c:419 n_hdlc_tty_wakeup+0x73/0xa0 drivers/tty/n_hdlc.c:496 tty_wakeup+0x92/0xb0 drivers/tty/tty_io.c:601 __start_tty.part.26+0x66/0x70 drivers/tty/tty_io.c:1018 __start_tty+0x34/0x40 drivers/tty/tty_io.c:1013 n_tty_ioctl_helper+0x146/0x1e0 drivers/tty/tty_ioctl.c:1138 n_hdlc_tty_ioctl+0xb3/0x2b0 drivers/tty/n_hdlc.c:794 tty_ioctl+0xa85/0x16d0 drivers/tty/tty_io.c:2992 vfs_ioctl fs/ioctl.c:43 [inline] do_vfs_ioctl+0x13e/0xba0 fs/ioctl.c:679 SYSC_ioctl fs/ioctl.c:694 [inline] SyS_ioctl+0x8f/0xc0 fs/ioctl.c:685 entry_SYSCALL_64_fastpath+0x1f/0xbd Signed-off-by: DaeRyong Jeong Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 5222805bfb15..07428642821d 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -114,16 +114,19 @@ static int pty_space(struct tty_struct *to) static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) { struct tty_struct *to = tty->link; + unsigned long flags; if (tty->stopped) return 0; if (c > 0) { + spin_lock_irqsave(&to->port->lock, flags); /* Stuff the data into the input queue of the other end */ c = tty_insert_flip_string(to->port, buf, c); /* And shovel */ if (c) tty_flip_buffer_push(to->port); + spin_unlock_irqrestore(&to->port->lock, flags); } return c; } From 95d6785b9a61f2db8608e054118132a7f81affef Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Wed, 9 May 2018 09:28:12 +0900 Subject: [PATCH 180/392] libata: Fix command retry decision [ Upstream commit 804689ad2d9b66d0d3920b48cf05881049d44589 ] For failed commands with valid sense data (e.g. NCQ commands), scsi_check_sense() is used in ata_analyze_tf() to determine if the command can be retried. In such case, rely on this decision and ignore the command error mask based decision done in ata_worth_retry(). This fixes useless retries of commands such as unaligned writes on zoned disks (TYPE_ZAC). Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Signed-off-by: Tejun Heo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-eh.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 9bdc1867137b..bdf540f8ca8a 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2173,12 +2173,16 @@ static void ata_eh_link_autopsy(struct ata_link *link) if (qc->err_mask & ~AC_ERR_OTHER) qc->err_mask &= ~AC_ERR_OTHER; - /* SENSE_VALID trumps dev/unknown error and revalidation */ + /* + * SENSE_VALID trumps dev/unknown error and revalidation. Upper + * layers will determine whether the command is worth retrying + * based on the sense data and device class/type. Otherwise, + * determine directly if the command is worth retrying using its + * error mask and flags. + */ if (qc->flags & ATA_QCFLAG_SENSE_VALID) qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); - - /* determine whether the command is worth retrying */ - if (ata_eh_worth_retry(qc)) + else if (ata_eh_worth_retry(qc)) qc->flags |= ATA_QCFLAG_RETRY; /* accumulate error info */ From cd181d859be102b85909af2e403ea0a68b17d090 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 4 May 2018 17:53:35 -0400 Subject: [PATCH 181/392] media: saa7164: Fix driver name in debug output [ Upstream commit 0cc4655cb57af0b7e105d075c4f83f8046efafe7 ] This issue was reported by a user who downloaded a corrupt saa7164 firmware, then went looking for a valid xc5000 firmware to fix the error displayed...but the device in question has no xc5000, thus after much effort, the wild goose chase eventually led to a support call. The xc5000 has nothing to do with saa7164 (as far as I can tell), so replace the string with saa7164 as well as give a meaningful hint on the firmware mismatch. Signed-off-by: Brad Love Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/pci/saa7164/saa7164-fw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c index 86763203d61d..021c46da794d 100644 --- a/drivers/media/pci/saa7164/saa7164-fw.c +++ b/drivers/media/pci/saa7164/saa7164-fw.c @@ -430,7 +430,8 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev) __func__, fw->size); if (fw->size != fwlength) { - printk(KERN_ERR "xc5000: firmware incorrect size\n"); + printk(KERN_ERR "saa7164: firmware incorrect size %zu != %u\n", + fw->size, fwlength); ret = -ENOMEM; goto out; } From bdd9b84854b65deca5e5bce02f57fecbe7b5ed49 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 8 May 2018 10:18:39 +0200 Subject: [PATCH 182/392] s390/cpum_sf: Add data entry sizes to sampling trailer entry [ Upstream commit 77715b7ddb446bd39a06f3376e85f4bb95b29bb8 ] The CPU Measurement sampling facility creates a trailer entry for each Sample-Data-Block of stored samples. The trailer entry contains the sizes (in bytes) of the stored sampling types: - basic-sampling data entry size - diagnostic-sampling data entry size Both sizes are 2 bytes long. This patch changes the trailer entry definition to reflect this. Fixes: fcc77f507333 ("s390/cpum_sf: Atomically reset trailer entry fields of sample-data-blocks") Signed-off-by: Thomas Richter Reviewed-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/cpu_mf.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index cb700d54bd83..b9ddb19048ad 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -134,7 +134,9 @@ struct hws_trailer_entry { unsigned int f:1; /* 0 - Block Full Indicator */ unsigned int a:1; /* 1 - Alert request control */ unsigned int t:1; /* 2 - Timestamp format */ - unsigned long long:61; /* 3 - 63: Reserved */ + unsigned int :29; /* 3 - 31: Reserved */ + unsigned int bsdes:16; /* 32-47: size of basic SDE */ + unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */ }; unsigned long long flags; /* 0 - 63: All indicators */ }; From 745255bd21c47468a70471c378080fcfded0b11c Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 8 May 2018 07:53:39 +0200 Subject: [PATCH 183/392] perf: fix invalid bit in diagnostic entry [ Upstream commit 3c0a83b14ea71fef5ccc93a3bd2de5f892be3194 ] The s390 CPU measurement facility sampling mode supports basic entries and diagnostic entries. Each entry has a valid bit to indicate the status of the entry as valid or invalid. This bit is bit 31 in the diagnostic entry, but the bit mask definition refers to bit 30. Fix this by making the reserved field one bit larger. Fixes: 7e75fc3ff4cf ("s390/cpum_sf: Add raw data sampling to support the diagnostic-sampling function") Signed-off-by: Thomas Richter Reviewed-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/cpu_mf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index b9ddb19048ad..0a1ca50298e8 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -118,7 +118,7 @@ struct hws_basic_entry { struct hws_diag_entry { unsigned int def:16; /* 0-15 Data Entry Format */ - unsigned int R:14; /* 16-19 and 20-30 reserved */ + unsigned int R:15; /* 16-19 and 20-30 reserved */ unsigned int I:1; /* 31 entry valid or invalid */ u8 data[]; /* Machine-dependent sample data */ } __packed; From 02b36483d5a368badd5876472f310e0b6d96b504 Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Mon, 7 May 2018 19:46:43 -0500 Subject: [PATCH 184/392] scsi: 3w-9xxx: fix a missing-check bug [ Upstream commit c9318a3e0218bc9dacc25be46b9eec363259536f ] In twa_chrdev_ioctl(), the ioctl driver command is firstly copied from the userspace pointer 'argp' and saved to the kernel object 'driver_command'. Then a security check is performed on the data buffer size indicated by 'driver_command', which is 'driver_command.buffer_length'. If the security check is passed, the entire ioctl command is copied again from the 'argp' pointer and saved to the kernel object 'tw_ioctl'. Then, various operations are performed on 'tw_ioctl' according to the 'cmd'. Given that the 'argp' pointer resides in userspace, a malicious userspace process can race to change the buffer size between the two copies. This way, the user can bypass the security check and inject invalid data buffer size. This can cause potential security issues in the following execution. This patch checks for capable(CAP_SYS_ADMIN) in twa_chrdev_open()t o avoid the above issues. Signed-off-by: Wenwen Wang Acked-by: Adam Radford Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/3w-9xxx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 6adf9abdf955..632295144766 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -901,6 +901,11 @@ static int twa_chrdev_open(struct inode *inode, struct file *file) unsigned int minor_number; int retval = TW_IOCTL_ERROR_OS_ENODEV; + if (!capable(CAP_SYS_ADMIN)) { + retval = -EACCES; + goto out; + } + minor_number = iminor(inode); if (minor_number >= twa_device_extension_count) goto out; From 120f719ade096921502045cab895914f9a3c02c8 Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Mon, 7 May 2018 19:54:01 -0500 Subject: [PATCH 185/392] scsi: 3w-xxxx: fix a missing-check bug [ Upstream commit 9899e4d3523faaef17c67141aa80ff2088f17871 ] In tw_chrdev_ioctl(), the length of the data buffer is firstly copied from the userspace pointer 'argp' and saved to the kernel object 'data_buffer_length'. Then a security check is performed on it to make sure that the length is not more than 'TW_MAX_IOCTL_SECTORS * 512'. Otherwise, an error code -EINVAL is returned. If the security check is passed, the entire ioctl command is copied again from the 'argp' pointer and saved to the kernel object 'tw_ioctl'. Then, various operations are performed on 'tw_ioctl' according to the 'cmd'. Given that the 'argp' pointer resides in userspace, a malicious userspace process can race to change the buffer length between the two copies. This way, the user can bypass the security check and inject invalid data buffer length. This can cause potential security issues in the following execution. This patch checks for capable(CAP_SYS_ADMIN) in tw_chrdev_open() to avoid the above issues. Signed-off-by: Wenwen Wang Acked-by: Adam Radford Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/3w-xxxx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index b327742b95ef..c1e1051f94cc 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1047,6 +1047,9 @@ static int tw_chrdev_open(struct inode *inode, struct file *file) dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n"); + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + minor_number = iminor(inode); if (minor_number >= tw_device_extension_count) return -ENODEV; From ac64c4d046cfbb59e7830f1a615d6a0286cb3abf Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 3 May 2018 13:54:32 +0300 Subject: [PATCH 186/392] scsi: megaraid: silence a static checker bug [ Upstream commit 27e833dabab74ee665e487e291c9afc6d71effba ] If we had more than 32 megaraid cards then it would cause memory corruption. That's not likely, of course, but it's handy to enforce it and make the static checker happy. Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/megaraid.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 2485255f3414..a8e6e32639ae 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4200,6 +4200,9 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) int irq, i, j; int error = -ENODEV; + if (hba_count >= MAX_CONTROLLERS) + goto out; + if (pci_enable_device(pdev)) goto out; pci_set_master(pdev); From 59b3c7d45af4dcf47213af559bc914b898573071 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 3 May 2018 18:37:17 -0700 Subject: [PATCH 187/392] bpf: fix references to free_bpf_prog_info() in comments [ Upstream commit ab7f5bf0928be2f148d000a6eaa6c0a36e74750e ] Comments in the verifier refer to free_bpf_prog_info() which seems to have never existed in tree. Replace it with free_used_maps(). Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Signed-off-by: Daniel Borkmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/verifier.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 76cd19dcb7f0..9c44a5ce40b3 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1763,7 +1763,7 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) /* hold the map. If the program is rejected by verifier, * the map will be released by release_maps() or it * will be used by the valid program until it's unloaded - * and all maps are released in free_bpf_prog_info() + * and all maps are released in free_used_maps() */ atomic_inc(&map->refcnt); @@ -1929,7 +1929,7 @@ int bpf_check(struct bpf_prog *prog, union bpf_attr *attr) free_env: if (!prog->aux->used_maps) /* if we didn't copy map pointers into bpf_prog_info, release - * them now. Otherwise free_bpf_prog_info() will release them. + * them now. Otherwise free_used_maps() will release them. */ release_maps(env); kfree(env); From 44daa6a4435a4a9ee456a8e99a8cd2acd70469eb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 20 Apr 2018 08:32:16 -0400 Subject: [PATCH 188/392] media: siano: get rid of __le32/__le16 cast warnings [ Upstream commit e1b7f11b37def5f3021c06e8c2b4953e099357aa ] Those are all false-positives that appear with smatch when building for arm: drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:67:35: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:67:35: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:67:35: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:67:35: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:98:26: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:98:26: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:98:26: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:98:26: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:99:28: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:99:28: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:99:28: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:99:28: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:100:27: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:100:27: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:100:27: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:100:27: warning: cast to restricted __le16 Get rid of them by adding explicit forced casts. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/common/siano/smsendian.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c index bfe831c10b1c..b95a631f23f9 100644 --- a/drivers/media/common/siano/smsendian.c +++ b/drivers/media/common/siano/smsendian.c @@ -35,7 +35,7 @@ void smsendian_handle_tx_message(void *buffer) switch (msg->x_msg_header.msg_type) { case MSG_SMS_DATA_DOWNLOAD_REQ: { - msg->msg_data[0] = le32_to_cpu(msg->msg_data[0]); + msg->msg_data[0] = le32_to_cpu((__force __le32)(msg->msg_data[0])); break; } @@ -44,7 +44,7 @@ void smsendian_handle_tx_message(void *buffer) sizeof(struct sms_msg_hdr))/4; for (i = 0; i < msg_words; i++) - msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); + msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); break; } @@ -64,7 +64,7 @@ void smsendian_handle_rx_message(void *buffer) { struct sms_version_res *ver = (struct sms_version_res *) msg; - ver->chip_model = le16_to_cpu(ver->chip_model); + ver->chip_model = le16_to_cpu((__force __le16)ver->chip_model); break; } @@ -81,7 +81,7 @@ void smsendian_handle_rx_message(void *buffer) sizeof(struct sms_msg_hdr))/4; for (i = 0; i < msg_words; i++) - msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); + msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); break; } @@ -95,9 +95,9 @@ void smsendian_handle_message_header(void *msg) #ifdef __BIG_ENDIAN struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)msg; - phdr->msg_type = le16_to_cpu(phdr->msg_type); - phdr->msg_length = le16_to_cpu(phdr->msg_length); - phdr->msg_flags = le16_to_cpu(phdr->msg_flags); + phdr->msg_type = le16_to_cpu((__force __le16)phdr->msg_type); + phdr->msg_length = le16_to_cpu((__force __le16)phdr->msg_length); + phdr->msg_flags = le16_to_cpu((__force __le16)phdr->msg_flags); #endif /* __BIG_ENDIAN */ } EXPORT_SYMBOL_GPL(smsendian_handle_message_header); From bf35cb47cc9265a482410b492ba9646aea408e8c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 2 May 2018 22:48:16 +0900 Subject: [PATCH 189/392] ALSA: hda/ca0132: fix build failure when a local macro is defined [ Upstream commit 8e142e9e628975b0dddd05cf1b095331dff6e2de ] DECLARE_TLV_DB_SCALE (alias of SNDRV_CTL_TLVD_DECLARE_DB_SCALE) is used but tlv.h is not included. This causes build failure when local macro is defined by comment-out. This commit fixes the bug. At the same time, the alias macro is replaced with a destination macro added at a commit 46e860f76804 ("ALSA: rename TLV-related macros so that they're friendly to user applications") Reported-by: Connor McAdams Fixes: 44f0c9782cc6 ('ALSA: hda/ca0132: Add tuning controls') Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_ca0132.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 4f7ffa8c4a0d..c1ecee56c7f9 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -38,6 +38,10 @@ /* Enable this to see controls for tuning purpose. */ /*#define ENABLE_TUNING_CONTROLS*/ +#ifdef ENABLE_TUNING_CONTROLS +#include +#endif + #define FLOAT_ZERO 0x00000000 #define FLOAT_ONE 0x3f800000 #define FLOAT_TWO 0x40000000 @@ -3037,8 +3041,8 @@ static int equalizer_ctl_put(struct snd_kcontrol *kcontrol, return 1; } -static const DECLARE_TLV_DB_SCALE(voice_focus_db_scale, 2000, 100, 0); -static const DECLARE_TLV_DB_SCALE(eq_db_scale, -2400, 100, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(voice_focus_db_scale, 2000, 100, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(eq_db_scale, -2400, 100, 0); static int add_tuning_control(struct hda_codec *codec, hda_nid_t pnid, hda_nid_t nid, From 3944d0e0307f03ad114d217193214971bc610776 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Tue, 24 Apr 2018 15:14:57 +0200 Subject: [PATCH 190/392] drm/gma500: fix psb_intel_lvds_mode_valid()'s return type [ Upstream commit 2ea009095c6e7396915a1d0dd480c41f02985f79 ] The method struct drm_connector_helper_funcs::mode_valid is defined as returning an 'enum drm_mode_status' but the driver implementation for this method, psb_intel_lvds_mode_valid(), uses an 'int' for it. Fix this by using 'enum drm_mode_status' for psb_intel_lvds_mode_valid(). Signed-off-by: Luc Van Oostenryck Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180424131458.2060-1-luc.vanoostenryck@gmail.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/gma500/psb_intel_drv.h | 2 +- drivers/gpu/drm/gma500/psb_intel_lvds.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 336bd3aa1a06..afdec6eb5b07 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -251,7 +251,7 @@ extern int intelfb_remove(struct drm_device *dev, extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); -extern int psb_intel_lvds_mode_valid(struct drm_connector *connector, +extern enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode); extern int psb_intel_lvds_set_property(struct drm_connector *connector, struct drm_property *property, diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index 48437f36ddf3..93986c056275 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -343,7 +343,7 @@ static void psb_intel_lvds_restore(struct drm_connector *connector) } } -int psb_intel_lvds_mode_valid(struct drm_connector *connector, +enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_psb_private *dev_priv = connector->dev->dev_private; From d06c846db135bbe3f7ddf65759f2387626a66596 Mon Sep 17 00:00:00 2001 From: Chris Novakovic Date: Tue, 24 Apr 2018 03:56:37 +0100 Subject: [PATCH 191/392] ipconfig: Correctly initialise ic_nameservers [ Upstream commit 300eec7c0a2495f771709c7642aa15f7cc148b83 ] ic_nameservers, which stores the list of name servers discovered by ipconfig, is initialised (i.e. has all of its elements set to NONE, or 0xffffffff) by ic_nameservers_predef() in the following scenarios: - before the "ip=" and "nfsaddrs=" kernel command line parameters are parsed (in ip_auto_config_setup()); - before autoconfiguring via DHCP or BOOTP (in ic_bootp_init()), in order to clear any values that may have been set after parsing "ip=" or "nfsaddrs=" and are no longer needed. This means that ic_nameservers_predef() is not called when neither "ip=" nor "nfsaddrs=" is specified on the kernel command line. In this scenario, every element in ic_nameservers remains set to 0x00000000, which is indistinguishable from ANY and causes pnp_seq_show() to write the following (bogus) information to /proc/net/pnp: #MANUAL nameserver 0.0.0.0 nameserver 0.0.0.0 nameserver 0.0.0.0 This is potentially problematic for systems that blindly link /etc/resolv.conf to /proc/net/pnp. Ensure that ic_nameservers is also initialised when neither "ip=" nor "nfsaddrs=" are specified by calling ic_nameservers_predef() in ip_auto_config(), but only when ip_auto_config_setup() was not called earlier. This causes the following to be written to /proc/net/pnp, and is consistent with what gets written when ipconfig is configured manually but no name servers are specified on the kernel command line: #MANUAL Signed-off-by: Chris Novakovic Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ipconfig.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 648fa1490ea7..3da772ae8808 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -772,6 +772,11 @@ static void __init ic_bootp_init_ext(u8 *e) */ static inline void __init ic_bootp_init(void) { + /* Re-initialise all name servers to NONE, in case any were set via the + * "ip=" or "nfsaddrs=" kernel command line parameters: any IP addresses + * specified there will already have been decoded but are no longer + * needed + */ ic_nameservers_predef(); dev_add_pack(&bootp_packet_type); @@ -1404,6 +1409,13 @@ static int __init ip_auto_config(void) int err; unsigned int i; + /* Initialise all name servers to NONE (but only if the "ip=" or + * "nfsaddrs=" kernel command line parameters weren't decoded, otherwise + * we'll overwrite the IP addresses specified there) + */ + if (ic_set_manually == 0) + ic_nameservers_predef(); + #ifdef CONFIG_PROC_FS proc_create("pnp", S_IRUGO, init_net.proc_net, &pnp_seq_fops); #endif /* CONFIG_PROC_FS */ @@ -1605,6 +1617,7 @@ static int __init ip_auto_config_setup(char *addrs) return 1; } + /* Initialise all name servers to NONE */ ic_nameservers_predef(); /* Parse string for static IP assignment. */ From d882e521074e1b7c8e22bcf21376fae5de58d82e Mon Sep 17 00:00:00 2001 From: Siva Rebbagondla Date: Wed, 11 Apr 2018 12:13:32 +0530 Subject: [PATCH 192/392] rsi: Fix 'invalid vdd' warning in mmc [ Upstream commit 78e450719c702784e42af6da912d3692fd3da0cb ] While performing cleanup, driver is messing with card->ocr value by not masking rocr against ocr_avail. Below panic is observed with some of the SDIO host controllers due to this. Issue is resolved by reverting incorrect modifications to vdd. [ 927.423821] mmc1: Invalid vdd 0x1f [ 927.423925] Modules linked in: rsi_sdio(+) cmac bnep arc4 rsi_91x mac80211 cfg80211 btrsi rfcomm bluetooth ecdh_generic [ 927.424073] CPU: 0 PID: 1624 Comm: insmod Tainted: G W 4.15.0-1000-caracalla #1 [ 927.424075] Hardware name: Dell Inc. Edge Gateway 3003/ , BIOS 01.00.06 01/22/2018 [ 927.424082] RIP: 0010:sdhci_set_power_noreg+0xdd/0x190[sdhci] [ 927.424085] RSP: 0018:ffffac3fc064b930 EFLAGS: 00010282 [ 927.424107] Call Trace: [ 927.424118] sdhci_set_power+0x5a/0x60 [sdhci] [ 927.424125] sdhci_set_ios+0x360/0x3b0 [sdhci] [ 927.424133] mmc_set_initial_state+0x92/0x120 [ 927.424137] mmc_power_up.part.34+0x33/0x1d0 [ 927.424141] mmc_power_up+0x17/0x20 [ 927.424147] mmc_sdio_runtime_resume+0x2d/0x50 [ 927.424151] mmc_runtime_resume+0x17/0x20 [ 927.424156] __rpm_callback+0xc4/0x200 [ 927.424161] ? idr_alloc_cyclic+0x57/0xd0 [ 927.424165] ? mmc_runtime_suspend+0x20/0x20 [ 927.424169] rpm_callback+0x24/0x80 [ 927.424172] ? mmc_runtime_suspend+0x20/0x20 [ 927.424176] rpm_resume+0x4b3/0x6c0 [ 927.424181] __pm_runtime_resume+0x4e/0x80 [ 927.424188] driver_probe_device+0x41/0x490 [ 927.424192] __driver_attach+0xdf/0xf0 [ 927.424196] ? driver_probe_device+0x490/0x490 [ 927.424201] bus_for_each_dev+0x6c/0xc0 [ 927.424205] driver_attach+0x1e/0x20 [ 927.424209] bus_add_driver+0x1f4/0x270 [ 927.424217] ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio] [ 927.424221] driver_register+0x60/0xe0 [ 927.424227] ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio] [ 927.424231] sdio_register_driver+0x20/0x30 [ 927.424237] rsi_module_init+0x16/0x40 [rsi_sdio] Signed-off-by: Siva Rebbagondla Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 8428858204a6..fc895b466ebb 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -155,7 +155,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) int err; struct mmc_card *card = pfunction->card; struct mmc_host *host = card->host; - s32 bit = (fls(host->ocr_avail) - 1); u8 cmd52_resp; u32 clock, resp, i; u16 rca; @@ -175,7 +174,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) msleep(20); /* Initialize the SDIO card */ - host->ios.vdd = bit; host->ios.chip_select = MMC_CS_DONTCARE; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.power_mode = MMC_POWER_UP; From 1813d388889169d63c9d1a75ca608d63a7c230cb Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 10 Apr 2018 15:05:42 +0200 Subject: [PATCH 193/392] microblaze: Fix simpleImage format generation [ Upstream commit ece97f3a5fb50cf5f98886fbc63c9665f2bb199d ] simpleImage generation was broken for some time. This patch is fixing steps how simpleImage.*.ub file is generated. Steps are objdump of vmlinux and create .ub. Also make sure that there is striped elf version with .strip suffix. Signed-off-by: Michal Simek Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/microblaze/boot/Makefile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile index 8e211cc28dac..e0f2afb98098 100644 --- a/arch/microblaze/boot/Makefile +++ b/arch/microblaze/boot/Makefile @@ -21,18 +21,20 @@ $(obj)/linux.bin.gz: $(obj)/linux.bin FORCE quiet_cmd_cp = CP $< $@$2 cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false) -quiet_cmd_strip = STRIP $@ +quiet_cmd_strip = STRIP $< $@$2 cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \ - -K _fdt_start vmlinux -o $@ + -K _fdt_start $< -o $@$2 UIMAGE_LOADADDR = $(CONFIG_KERNEL_BASE_ADDR) +UIMAGE_IN = $@ +UIMAGE_OUT = $@.ub $(obj)/simpleImage.%: vmlinux FORCE $(call if_changed,cp,.unstrip) $(call if_changed,objcopy) $(call if_changed,uimage) - $(call if_changed,strip) - @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' + $(call if_changed,strip,.strip) + @echo 'Kernel: $(UIMAGE_OUT) is ready' ' (#'`cat .version`')' clean-files += simpleImage.*.unstrip linux.bin.ub From 1b2c23459c3335ee9e0dd2cd2e2856d0201852e5 Mon Sep 17 00:00:00 2001 From: Dominik Bozek Date: Fri, 13 Apr 2018 10:42:31 -0700 Subject: [PATCH 194/392] usb: hub: Don't wait for connect state at resume for powered-off ports [ Upstream commit 5d111f5190848d6fb1c414dc57797efea3526a2f ] wait_for_connected() wait till a port change status to USB_PORT_STAT_CONNECTION, but this is not possible if the port is unpowered. The loop will only exit at timeout. Such case take place if an over-current incident happen while system is in S3. Then during resume wait_for_connected() will wait 2s, which may be noticeable by the user. Signed-off-by: Dominik Bozek Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 3d15b5fc9336..164fdeddfc05 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3310,6 +3310,10 @@ static int wait_for_ss_port_enable(struct usb_device *udev, while (delay_ms < 2000) { if (status || *portstatus & USB_PORT_STAT_CONNECTION) break; + if (!port_is_power_on(hub, *portstatus)) { + status = -ENODEV; + break; + } msleep(20); delay_ms += 20; status = hub_port_status(hub, *port1, portstatus, portchange); From da49259e29bc6b44acee52a9d93f89432bb893fd Mon Sep 17 00:00:00 2001 From: Tudor-Dan Ambarus Date: Tue, 3 Apr 2018 09:39:01 +0300 Subject: [PATCH 195/392] crypto: authencesn - don't leak pointers to authenc keys [ Upstream commit 31545df391d58a3bb60e29b1192644a6f2b5a8dd ] In crypto_authenc_esn_setkey we save pointers to the authenc keys in a local variable of type struct crypto_authenc_keys and we don't zeroize it after use. Fix this and don't leak pointers to the authenc keys. Signed-off-by: Tudor Ambarus Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- crypto/authencesn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/authencesn.c b/crypto/authencesn.c index 024bff2344fc..c248a966aa5b 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -86,6 +86,7 @@ static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 * CRYPTO_TFM_RES_MASK); out: + memzero_explicit(&keys, sizeof(keys)); return err; badkey: From 75a89c2ada6f42ec30e093f6c97e003600c074ab Mon Sep 17 00:00:00 2001 From: Tudor-Dan Ambarus Date: Tue, 3 Apr 2018 09:39:00 +0300 Subject: [PATCH 196/392] crypto: authenc - don't leak pointers to authenc keys [ Upstream commit ad2fdcdf75d169e7a5aec6c7cb421c0bec8ec711 ] In crypto_authenc_setkey we save pointers to the authenc keys in a local variable of type struct crypto_authenc_keys and we don't zeroize it after use. Fix this and don't leak pointers to the authenc keys. Signed-off-by: Tudor Ambarus Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- crypto/authenc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/authenc.c b/crypto/authenc.c index 78fb16cab13f..eb029ea72f98 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -112,6 +112,7 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, CRYPTO_TFM_RES_MASK); out: + memzero_explicit(&keys, sizeof(keys)); return err; badkey: From 0c567f08fdbe1750294cbf3d45d883777c3e1155 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 14 Mar 2018 11:41:36 -0400 Subject: [PATCH 197/392] media: omap3isp: fix unbalanced dma_iommu_mapping [ Upstream commit b7e1e6859fbf60519fd82d7120cee106a6019512 ] The OMAP3 ISP driver manages its MMU mappings through the IOMMU-aware ARM DMA backend. The current code creates a dma_iommu_mapping and attaches this to the ISP device, but never detaches the mapping in either the probe failure paths or the driver remove path resulting in an unbalanced mapping refcount and a memory leak. Fix this properly. Reported-by: Pavel Machek Signed-off-by: Suman Anna Tested-by: Pavel Machek Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/omap3isp/isp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 233eccc5c33e..3e91109b205d 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2117,6 +2117,7 @@ static int isp_initialize_modules(struct isp_device *isp) static void isp_detach_iommu(struct isp_device *isp) { + arm_iommu_detach_device(isp->dev); arm_iommu_release_mapping(isp->mapping); isp->mapping = NULL; iommu_group_remove_device(isp->dev); @@ -2150,8 +2151,7 @@ static int isp_attach_iommu(struct isp_device *isp) mapping = arm_iommu_create_mapping(&platform_bus_type, SZ_1G, SZ_2G); if (IS_ERR(mapping)) { dev_err(isp->dev, "failed to create ARM IOMMU mapping\n"); - ret = PTR_ERR(mapping); - goto error; + return PTR_ERR(mapping); } isp->mapping = mapping; @@ -2166,7 +2166,8 @@ static int isp_attach_iommu(struct isp_device *isp) return 0; error: - isp_detach_iommu(isp); + arm_iommu_release_mapping(isp->mapping); + isp->mapping = NULL; return ret; } From 9c2663418fae42a6f13917bd91f67d5d1d3e650a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 6 Apr 2018 07:54:51 -0400 Subject: [PATCH 198/392] media: si470x: fix __be16 annotations [ Upstream commit 90db5c829692a0a7845e977e45719b4699216bd4 ] The annotations there are wrong as warned: drivers/media/radio/si470x/radio-si470x-i2c.c:107:35: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:107:35: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:107:35: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:107:35: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:129:24: warning: incorrect type in assignment (different base types) drivers/media/radio/si470x/radio-si470x-i2c.c:129:24: expected unsigned short [unsigned] [short] drivers/media/radio/si470x/radio-si470x-i2c.c:129:24: got restricted __be16 [usertype] drivers/media/radio/si470x/radio-si470x-i2c.c:163:39: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:163:39: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:163:39: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:163:39: warning: cast to restricted __be16 Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/radio/si470x/radio-si470x-i2c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 2a497c80c77f..80261e556367 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -96,7 +96,7 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); */ int si470x_get_register(struct si470x_device *radio, int regnr) { - u16 buf[READ_REG_NUM]; + __be16 buf[READ_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, @@ -121,7 +121,7 @@ int si470x_get_register(struct si470x_device *radio, int regnr) int si470x_set_register(struct si470x_device *radio, int regnr) { int i; - u16 buf[WRITE_REG_NUM]; + __be16 buf[WRITE_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, @@ -151,7 +151,7 @@ int si470x_set_register(struct si470x_device *radio, int regnr) static int si470x_get_all_registers(struct si470x_device *radio) { int i; - u16 buf[READ_REG_NUM]; + __be16 buf[READ_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, From 84b819b34c0474994f8124fe6d4b86dec50f56eb Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 14 Jul 2018 23:55:57 -0400 Subject: [PATCH 199/392] random: mix rdrand with entropy sent in from userspace commit 81e69df38e2911b642ec121dec319fad2a4782f3 upstream. Fedora has integrated the jitter entropy daemon to work around slow boot problems, especially on VM's that don't support virtio-rng: https://bugzilla.redhat.com/show_bug.cgi?id=1572944 It's understandable why they did this, but the Jitter entropy daemon works fundamentally on the principle: "the CPU microarchitecture is **so** complicated and we can't figure it out, so it *must* be random". Yes, it uses statistical tests to "prove" it is secure, but AES_ENCRYPT(NSA_KEY, COUNTER++) will also pass statistical tests with flying colors. So if RDRAND is available, mix it into entropy submitted from userspace. It can't hurt, and if you believe the NSA has backdoored RDRAND, then they probably have enough details about the Intel microarchitecture that they can reverse engineer how the Jitter entropy daemon affects the microarchitecture, and attack its output stream. And if RDRAND is in fact an honest DRNG, it will immeasurably improve on what the Jitter entropy daemon might produce. This also provides some protection against someone who is able to read or set the entropy seed file. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 4ba5c7e4e254..28970b8e4564 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1417,14 +1417,22 @@ static int write_pool(struct entropy_store *r, const char __user *buffer, size_t count) { size_t bytes; - __u32 buf[16]; + __u32 t, buf[16]; const char __user *p = buffer; while (count > 0) { + int b, i = 0; + bytes = min(count, sizeof(buf)); if (copy_from_user(&buf, p, bytes)) return -EFAULT; + for (b = bytes ; b > 0 ; b -= sizeof(__u32), i++) { + if (!arch_get_random_int(&t)) + break; + buf[i] ^= t; + } + count -= bytes; p += bytes; From 2474de0a61ad4c3756dd6b834807d929215eb899 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 29 Jul 2018 12:44:46 -0700 Subject: [PATCH 200/392] squashfs: be more careful about metadata corruption commit 01cfb7937a9af2abb1136c7e89fbf3fd92952956 upstream. Anatoly Trosinenko reports that a corrupted squashfs image can cause a kernel oops. It turns out that squashfs can end up being confused about negative fragment lengths. The regular squashfs_read_data() does check for negative lengths, but squashfs_read_metadata() did not, and the fragment size code just blindly trusted the on-disk value. Fix both the fragment parsing and the metadata reading code. Reported-by: Anatoly Trosinenko Cc: Al Viro Cc: Phillip Lougher Cc: stable@kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/squashfs/cache.c | 3 +++ fs/squashfs/file.c | 8 ++++++-- fs/squashfs/fragment.c | 4 +--- fs/squashfs/squashfs_fs.h | 6 ++++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c index 1cb70a0b2168..91ce49c05b7c 100644 --- a/fs/squashfs/cache.c +++ b/fs/squashfs/cache.c @@ -350,6 +350,9 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer, TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset); + if (unlikely(length < 0)) + return -EIO; + while (length) { entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0); if (entry->error) { diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c index e5c9689062ba..1ec7bae2751d 100644 --- a/fs/squashfs/file.c +++ b/fs/squashfs/file.c @@ -194,7 +194,11 @@ static long long read_indexes(struct super_block *sb, int n, } for (i = 0; i < blocks; i++) { - int size = le32_to_cpu(blist[i]); + int size = squashfs_block_size(blist[i]); + if (size < 0) { + err = size; + goto failure; + } block += SQUASHFS_COMPRESSED_SIZE_BLOCK(size); } n -= blocks; @@ -367,7 +371,7 @@ static int read_blocklist(struct inode *inode, int index, u64 *block) sizeof(size)); if (res < 0) return res; - return le32_to_cpu(size); + return squashfs_block_size(size); } /* Copy data into page cache */ diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c index 0ed6edbc5c71..86ad9a4b8c36 100644 --- a/fs/squashfs/fragment.c +++ b/fs/squashfs/fragment.c @@ -61,9 +61,7 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, return size; *fragment_block = le64_to_cpu(fragment_entry.start_block); - size = le32_to_cpu(fragment_entry.size); - - return size; + return squashfs_block_size(fragment_entry.size); } diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index 4b2beda49498..b83ba580d907 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h @@ -129,6 +129,12 @@ #define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) +static inline int squashfs_block_size(__le32 raw) +{ + u32 size = le32_to_cpu(raw); + return (size >> 25) ? -EIO : size; +} + /* * Inode number ops. Inodes consist of a compressed block number, and an * uncompressed offset within that block From 30a1af4f5ab1d457afade268298f9f9f3943a2dc Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Thu, 26 Jul 2018 15:05:37 +0300 Subject: [PATCH 201/392] NET: stmmac: align DMA stuff to largest cache line length [ Upstream commit 9939a46d90c6c76f4533d534dbadfa7b39dc6acc ] As for today STMMAC_ALIGN macro (which is used to align DMA stuff) relies on L1 line length (L1_CACHE_BYTES). This isn't correct in case of system with several cache levels which might have L1 cache line length smaller than L2 line. This can lead to sharing one cache line between DMA buffer and other data, so we can lose this data while invalidate DMA buffer before DMA transaction. Fix that by using SMP_CACHE_BYTES instead of L1_CACHE_BYTES for aligning. Signed-off-by: Eugeniy Paltsev Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 103ae8ef8643..fc7b5ac6d6fe 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -53,7 +53,7 @@ #include "stmmac.h" #include -#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) +#define STMMAC_ALIGN(x) __ALIGN_KERNEL(x, SMP_CACHE_BYTES) /* Module parameters */ #define TX_TIMEO 5000 From fb062d5267ecdf55d8e7bc4765aa3f6b9e7388b7 Mon Sep 17 00:00:00 2001 From: Xiao Liang Date: Fri, 27 Jul 2018 17:56:08 +0800 Subject: [PATCH 202/392] xen-netfront: wait xenbus state change when load module manually [ Upstream commit 822fb18a82abaf4ee7058793d95d340f5dab7bfc ] When loading module manually, after call xenbus_switch_state to initializes the state of the netfront device, the driver state did not change so fast that may lead no dev created in latest kernel. This patch adds wait to make sure xenbus knows the driver is not in closed/unknown state. Current state: [vm]# ethtool eth0 Settings for eth0: Link detected: yes [vm]# modprobe -r xen_netfront [vm]# modprobe xen_netfront [vm]# ethtool eth0 Settings for eth0: Cannot get device settings: No such device Cannot get wake-on-lan settings: No such device Cannot get message level: No such device Cannot get link status: No such device No data available With the patch installed. [vm]# ethtool eth0 Settings for eth0: Link detected: yes [vm]# modprobe -r xen_netfront [vm]# modprobe xen_netfront [vm]# ethtool eth0 Settings for eth0: Link detected: yes Signed-off-by: Xiao Liang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netfront.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 9967733a397e..584d035ec0dd 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -85,6 +85,7 @@ struct netfront_cb { /* IRQ name is queue name with "-tx" or "-rx" appended */ #define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3) +static DECLARE_WAIT_QUEUE_HEAD(module_load_q); static DECLARE_WAIT_QUEUE_HEAD(module_unload_q); struct netfront_stats { @@ -1359,6 +1360,11 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) netif_carrier_off(netdev); xenbus_switch_state(dev, XenbusStateInitialising); + wait_event(module_load_q, + xenbus_read_driver_state(dev->otherend) != + XenbusStateClosed && + xenbus_read_driver_state(dev->otherend) != + XenbusStateUnknown); return netdev; exit: From de0e6404535a0455d4d0c81ebf98c9ea2599ccab Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 17 May 2018 14:47:25 -0700 Subject: [PATCH 203/392] tcp: do not force quickack when receiving out-of-order packets [ Upstream commit a3893637e1eb0ef5eb1bbc52b3a8d2dfa317a35d ] As explained in commit 9f9843a751d0 ("tcp: properly handle stretch acks in slow start"), TCP stacks have to consider how many packets are acknowledged in one single ACK, because of GRO, but also because of ACK compression or losses. We plan to add SACK compression in the following patch, we must therefore not call tcp_enter_quickack_mode() Signed-off-by: Eric Dumazet Acked-by: Neal Cardwell Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index dee70277f12f..8e0d7889485b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4512,8 +4512,6 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt + tcp_receive_window(tp))) goto out_of_window; - tcp_enter_quickack_mode(sk); - if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { /* Partial packet, seq < rcv_next < end_seq */ SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n", From c4af434936605e294485f220d0f92e956ccbd58d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 21 May 2018 15:08:56 -0700 Subject: [PATCH 204/392] tcp: add max_quickacks param to tcp_incr_quickack and tcp_enter_quickack_mode [ Upstream commit 9a9c9b51e54618861420093ae6e9b50a961914c5 ] We want to add finer control of the number of ACK packets sent after ECN events. This patch is not changing current behavior, it only enables following change. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/tcp.h | 2 +- net/ipv4/tcp_dctcp.c | 4 ++-- net/ipv4/tcp_input.c | 24 +++++++++++++----------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index b362f9abae3b..bca27ae031e2 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -372,7 +372,7 @@ ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); -void tcp_enter_quickack_mode(struct sock *sk); +void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks); static inline void tcp_dec_quickack_mode(struct sock *sk, const unsigned int pkts) { diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index ddd84ed7fb38..583b9935ebb5 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -135,7 +135,7 @@ static void dctcp_ce_state_0_to_1(struct sock *sk) */ if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) __tcp_send_ack(sk, ca->prior_rcv_nxt); - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, 1); } ca->prior_rcv_nxt = tp->rcv_nxt; @@ -156,7 +156,7 @@ static void dctcp_ce_state_1_to_0(struct sock *sk) */ if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) __tcp_send_ack(sk, ca->prior_rcv_nxt); - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, 1); } ca->prior_rcv_nxt = tp->rcv_nxt; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 8e0d7889485b..f1deaa323c1f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -171,21 +171,23 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb) } } -static void tcp_incr_quickack(struct sock *sk) +static void tcp_incr_quickack(struct sock *sk, unsigned int max_quickacks) { struct inet_connection_sock *icsk = inet_csk(sk); unsigned int quickacks = tcp_sk(sk)->rcv_wnd / (2 * icsk->icsk_ack.rcv_mss); if (quickacks == 0) quickacks = 2; + quickacks = min(quickacks, max_quickacks); if (quickacks > icsk->icsk_ack.quick) - icsk->icsk_ack.quick = min(quickacks, TCP_MAX_QUICKACKS); + icsk->icsk_ack.quick = quickacks; } -void tcp_enter_quickack_mode(struct sock *sk) +void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks) { struct inet_connection_sock *icsk = inet_csk(sk); - tcp_incr_quickack(sk); + + tcp_incr_quickack(sk, max_quickacks); icsk->icsk_ack.pingpong = 0; icsk->icsk_ack.ato = TCP_ATO_MIN; } @@ -228,7 +230,7 @@ static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) * it is probably a retransmit. */ if (tp->ecn_flags & TCP_ECN_SEEN) - tcp_enter_quickack_mode((struct sock *)tp); + tcp_enter_quickack_mode((struct sock *)tp, TCP_MAX_QUICKACKS); break; case INET_ECN_CE: if (tcp_ca_needs_ecn((struct sock *)tp)) @@ -236,7 +238,7 @@ static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { /* Better not delay acks, sender can have a very low cwnd */ - tcp_enter_quickack_mode((struct sock *)tp); + tcp_enter_quickack_mode((struct sock *)tp, TCP_MAX_QUICKACKS); tp->ecn_flags |= TCP_ECN_DEMAND_CWR; } tp->ecn_flags |= TCP_ECN_SEEN; @@ -644,7 +646,7 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) /* The _first_ data packet received, initialize * delayed ACK engine. */ - tcp_incr_quickack(sk); + tcp_incr_quickack(sk, TCP_MAX_QUICKACKS); icsk->icsk_ack.ato = TCP_ATO_MIN; } else { int m = now - icsk->icsk_ack.lrcvtime; @@ -660,7 +662,7 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) /* Too long gap. Apparently sender failed to * restart window, so that we send ACKs quickly. */ - tcp_incr_quickack(sk); + tcp_incr_quickack(sk, TCP_MAX_QUICKACKS); sk_mem_reclaim(sk); } } @@ -4001,7 +4003,7 @@ static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb) if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); if (tcp_is_sack(tp) && sysctl_tcp_dsack) { u32 end_seq = TCP_SKB_CB(skb)->end_seq; @@ -4501,7 +4503,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); out_of_window: - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); inet_csk_schedule_ack(sk); drop: __kfree_skb(skb); @@ -5521,7 +5523,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, * to stand against the temptation 8) --ANK */ inet_csk_schedule_ack(sk); - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, TCP_DELACK_MAX, TCP_RTO_MAX); From d8c80fae49027ee5fce46df8f9bcc92d4b855771 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 21 May 2018 15:08:57 -0700 Subject: [PATCH 205/392] tcp: do not aggressively quick ack after ECN events [ Upstream commit 522040ea5fdd1c33bbf75e1d7c7c0422b96a94ef ] ECN signals currently forces TCP to enter quickack mode for up to 16 (TCP_MAX_QUICKACKS) following incoming packets. We believe this is not needed, and only sending one immediate ack for the current packet should be enough. This should reduce the extra load noticed in DCTCP environments, after congestion events. This is part 2 of our effort to reduce pure ACK packets. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index f1deaa323c1f..8b7e946094a4 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -230,7 +230,7 @@ static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) * it is probably a retransmit. */ if (tp->ecn_flags & TCP_ECN_SEEN) - tcp_enter_quickack_mode((struct sock *)tp, TCP_MAX_QUICKACKS); + tcp_enter_quickack_mode((struct sock *)tp, 1); break; case INET_ECN_CE: if (tcp_ca_needs_ecn((struct sock *)tp)) @@ -238,7 +238,7 @@ static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { /* Better not delay acks, sender can have a very low cwnd */ - tcp_enter_quickack_mode((struct sock *)tp, TCP_MAX_QUICKACKS); + tcp_enter_quickack_mode((struct sock *)tp, 1); tp->ecn_flags |= TCP_ECN_DEMAND_CWR; } tp->ecn_flags |= TCP_ECN_SEEN; From 0ecfeef99e88e66ae9c2a9555be4eb43908b463c Mon Sep 17 00:00:00 2001 From: Yousuk Seung Date: Mon, 4 Jun 2018 15:29:51 -0700 Subject: [PATCH 206/392] tcp: refactor tcp_ecn_check_ce to remove sk type cast [ Upstream commit f4c9f85f3b2cb7669830cd04d0be61192a4d2436 ] Refactor tcp_ecn_check_ce and __tcp_ecn_check_ce to accept struct sock* instead of tcp_sock* to clean up type casts. This is a pure refactor patch. Signed-off-by: Yousuk Seung Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 8b7e946094a4..90f12c329b83 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -221,8 +221,10 @@ static void tcp_ecn_withdraw_cwr(struct tcp_sock *tp) tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; } -static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) +static void __tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb) { + struct tcp_sock *tp = tcp_sk(sk); + switch (TCP_SKB_CB(skb)->ip_dsfield & INET_ECN_MASK) { case INET_ECN_NOT_ECT: /* Funny extension: if ECT is not set on a segment, @@ -230,31 +232,31 @@ static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) * it is probably a retransmit. */ if (tp->ecn_flags & TCP_ECN_SEEN) - tcp_enter_quickack_mode((struct sock *)tp, 1); + tcp_enter_quickack_mode(sk, 1); break; case INET_ECN_CE: - if (tcp_ca_needs_ecn((struct sock *)tp)) - tcp_ca_event((struct sock *)tp, CA_EVENT_ECN_IS_CE); + if (tcp_ca_needs_ecn(sk)) + tcp_ca_event(sk, CA_EVENT_ECN_IS_CE); if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { /* Better not delay acks, sender can have a very low cwnd */ - tcp_enter_quickack_mode((struct sock *)tp, 1); + tcp_enter_quickack_mode(sk, 1); tp->ecn_flags |= TCP_ECN_DEMAND_CWR; } tp->ecn_flags |= TCP_ECN_SEEN; break; default: - if (tcp_ca_needs_ecn((struct sock *)tp)) - tcp_ca_event((struct sock *)tp, CA_EVENT_ECN_NO_CE); + if (tcp_ca_needs_ecn(sk)) + tcp_ca_event(sk, CA_EVENT_ECN_NO_CE); tp->ecn_flags |= TCP_ECN_SEEN; break; } } -static void tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) +static void tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb) { - if (tp->ecn_flags & TCP_ECN_OK) - __tcp_ecn_check_ce(tp, skb); + if (tcp_sk(sk)->ecn_flags & TCP_ECN_OK) + __tcp_ecn_check_ce(sk, skb); } static void tcp_ecn_rcv_synack(struct tcp_sock *tp, const struct tcphdr *th) @@ -668,7 +670,7 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) } icsk->icsk_ack.lrcvtime = now; - tcp_ecn_check_ce(tp, skb); + tcp_ecn_check_ce(sk, skb); if (skb->len >= 128) tcp_grow_window(sk, skb); @@ -4231,7 +4233,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) struct sk_buff *skb1; u32 seq, end_seq; - tcp_ecn_check_ce(tp, skb); + tcp_ecn_check_ce(sk, skb); if (unlikely(tcp_try_rmem_schedule(sk, skb, skb->truesize))) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPOFODROP); From 6f46f91cb5727c7ecf7a2475245517da85b7bc5a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 Jun 2018 08:47:21 -0700 Subject: [PATCH 207/392] tcp: add one more quick ack after after ECN events [ Upstream commit 15ecbe94a45ef88491ca459b26efdd02f91edb6d ] Larry Brakmo proposal ( https://patchwork.ozlabs.org/patch/935233/ tcp: force cwnd at least 2 in tcp_cwnd_reduction) made us rethink about our recent patch removing ~16 quick acks after ECN events. tcp_enter_quickack_mode(sk, 1) makes sure one immediate ack is sent, but in the case the sender cwnd was lowered to 1, we do not want to have a delayed ack for the next packet we will receive. Fixes: 522040ea5fdd ("tcp: do not aggressively quick ack after ECN events") Signed-off-by: Eric Dumazet Reported-by: Neal Cardwell Cc: Lawrence Brakmo Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 90f12c329b83..f8364cfd2cdb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -232,7 +232,7 @@ static void __tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb) * it is probably a retransmit. */ if (tp->ecn_flags & TCP_ECN_SEEN) - tcp_enter_quickack_mode(sk, 1); + tcp_enter_quickack_mode(sk, 2); break; case INET_ECN_CE: if (tcp_ca_needs_ecn(sk)) @@ -240,7 +240,7 @@ static void __tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb) if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { /* Better not delay acks, sender can have a very low cwnd */ - tcp_enter_quickack_mode(sk, 1); + tcp_enter_quickack_mode(sk, 2); tp->ecn_flags |= TCP_ECN_DEMAND_CWR; } tp->ecn_flags |= TCP_ECN_SEEN; From 88b3bd57867606b98fc04be05b4aa299f1587780 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 27 Jul 2018 18:15:46 +0200 Subject: [PATCH 208/392] ipv4: remove BUG_ON() from fib_compute_spec_dst [ Upstream commit 9fc12023d6f51551d6ca9ed7e02ecc19d79caf17 ] Remove BUG_ON() from fib_compute_spec_dst routine and check in_dev pointer during flowi4 data structure initialization. fib_compute_spec_dst routine can be run concurrently with device removal where ip_ptr net_device pointer is set to NULL. This can happen if userspace enables pkt info on UDP rx socket and the device is removed while traffic is flowing Fixes: 35ebf65e851c ("ipv4: Create and use fib_compute_spec_dst() helper") Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/fib_frontend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index db8a9840ffac..0b29649627a7 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -209,19 +209,19 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb) return ip_hdr(skb)->daddr; in_dev = __in_dev_get_rcu(dev); - BUG_ON(!in_dev); net = dev_net(dev); scope = RT_SCOPE_UNIVERSE; if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) { + bool vmark = in_dev && IN_DEV_SRC_VMARK(in_dev); fl4.flowi4_oif = 0; fl4.flowi4_iif = LOOPBACK_IFINDEX; fl4.daddr = ip_hdr(skb)->saddr; fl4.saddr = 0; fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); fl4.flowi4_scope = scope; - fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; + fl4.flowi4_mark = vmark ? skb->mark : 0; if (!fib_lookup(net, &fl4, &res)) return FIB_RES_PREFSRC(net, res); } else { From 95478b56ac4fddc84ade05c4cf95a524af58d16c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 30 Jul 2018 20:09:11 -0700 Subject: [PATCH 209/392] inet: frag: enforce memory limits earlier [ Upstream commit 56e2c94f055d328f5f6b0a5c1721cca2f2d4e0a1 ] We currently check current frags memory usage only when a new frag queue is created. This allows attackers to first consume the memory budget (default : 4 MB) creating thousands of frag queues, then sending tiny skbs to exceed high_thresh limit by 2 to 3 order of magnitude. Note that before commit 648700f76b03 ("inet: frags: use rhashtables for reassembly units"), work queue could be starved under DOS, getting no cpu cycles. After commit 648700f76b03, only the per frag queue timer can eventually remove an incomplete frag queue and its skbs. Fixes: b13d3cbfb8e8 ("inet: frag: move eviction of queues to work queue") Signed-off-by: Eric Dumazet Reported-by: Jann Horn Cc: Florian Westphal Cc: Peter Oskolkov Cc: Paolo Abeni Acked-by: Florian Westphal Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/inet_fragment.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 19419b60cb37..0d950edb33c2 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -379,11 +379,6 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, { struct inet_frag_queue *q; - if (frag_mem_limit(nf) > nf->high_thresh) { - inet_frag_schedule_worker(f); - return NULL; - } - q = kmem_cache_zalloc(f->frags_cachep, GFP_ATOMIC); if (q == NULL) return NULL; @@ -420,6 +415,11 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, struct inet_frag_queue *q; int depth = 0; + if (!nf->high_thresh || frag_mem_limit(nf) > nf->high_thresh) { + inet_frag_schedule_worker(f); + return NULL; + } + if (frag_mem_limit(nf) > nf->low_thresh) inet_frag_schedule_worker(f); From 1aa222b3b245f2e656b90271b9994232f9b786a2 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 31 Jul 2018 17:12:52 -0700 Subject: [PATCH 210/392] net: dsa: Do not suspend/resume closed slave_dev [ Upstream commit a94c689e6c9e72e722f28339e12dff191ee5a265 ] If a DSA slave network device was previously disabled, there is no need to suspend or resume it. Fixes: 2446254915a7 ("net: dsa: allow switch drivers to implement suspend/resume hooks") Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dsa/slave.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index ab03e00ffe8f..95f63b79f03e 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -503,6 +503,9 @@ int dsa_slave_suspend(struct net_device *slave_dev) { struct dsa_slave_priv *p = netdev_priv(slave_dev); + if (!netif_running(slave_dev)) + return 0; + netif_device_detach(slave_dev); if (p->phy) { @@ -520,6 +523,9 @@ int dsa_slave_resume(struct net_device *slave_dev) { struct dsa_slave_priv *p = netdev_priv(slave_dev); + if (!netif_running(slave_dev)) + return 0; + netif_device_attach(slave_dev); if (p->phy) { From a220a703b9d844662104f5db3862f12eb426c758 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 30 Jul 2018 14:27:15 -0700 Subject: [PATCH 211/392] squashfs: more metadata hardening commit d512584780d3e6a7cacb2f482834849453d444a1 upstream. Anatoly reports another squashfs fuzzing issue, where the decompression parameters themselves are in a compressed block. This causes squashfs_read_data() to be called in order to read the decompression options before the decompression stream having been set up, making squashfs go sideways. Reported-by: Anatoly Trosinenko Acked-by: Phillip Lougher Cc: stable@kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/squashfs/block.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c index 0cea9b9236d0..82bc942fc437 100644 --- a/fs/squashfs/block.c +++ b/fs/squashfs/block.c @@ -166,6 +166,8 @@ int squashfs_read_data(struct super_block *sb, u64 index, int length, } if (compressed) { + if (!msblk->stream) + goto read_failure; length = squashfs_decompress(msblk, bh, b, offset, length, output); if (length < 0) From 4a60e5435410a27e7daea64d1ed550dd8238936b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 2 Aug 2018 08:43:35 -0700 Subject: [PATCH 212/392] squashfs: more metadata hardenings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 71755ee5350b63fb1f283de8561cdb61b47f4d1d upstream. The squashfs fragment reading code doesn't actually verify that the fragment is inside the fragment table. The end result _is_ verified to be inside the image when actually reading the fragment data, but before that is done, we may end up taking a page fault because the fragment table itself might not even exist. Another report from Anatoly and his endless squashfs image fuzzing. Reported-by: Анатолий Тросиненко Acked-by:: Phillip Lougher , Cc: Willy Tarreau Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/squashfs/fragment.c | 13 +++++++++---- fs/squashfs/squashfs_fs_sb.h | 1 + fs/squashfs/super.c | 5 +++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c index 86ad9a4b8c36..0681feab4a84 100644 --- a/fs/squashfs/fragment.c +++ b/fs/squashfs/fragment.c @@ -49,11 +49,16 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, u64 *fragment_block) { struct squashfs_sb_info *msblk = sb->s_fs_info; - int block = SQUASHFS_FRAGMENT_INDEX(fragment); - int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); - u64 start_block = le64_to_cpu(msblk->fragment_index[block]); + int block, offset, size; struct squashfs_fragment_entry fragment_entry; - int size; + u64 start_block; + + if (fragment >= msblk->fragments) + return -EIO; + block = SQUASHFS_FRAGMENT_INDEX(fragment); + offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); + + start_block = le64_to_cpu(msblk->fragment_index[block]); size = squashfs_read_metadata(sb, &fragment_entry, &start_block, &offset, sizeof(fragment_entry)); diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index 1da565cb50c3..ef69c31947bf 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h @@ -75,6 +75,7 @@ struct squashfs_sb_info { unsigned short block_log; long long bytes_used; unsigned int inodes; + unsigned int fragments; int xattr_ids; }; #endif diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 5056babe00df..93aa3e23c845 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -176,6 +176,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) msblk->inode_table = le64_to_cpu(sblk->inode_table_start); msblk->directory_table = le64_to_cpu(sblk->directory_table_start); msblk->inodes = le32_to_cpu(sblk->inodes); + msblk->fragments = le32_to_cpu(sblk->fragments); flags = le16_to_cpu(sblk->flags); TRACE("Found valid superblock on %s\n", bdevname(sb->s_bdev, b)); @@ -186,7 +187,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) TRACE("Filesystem size %lld bytes\n", msblk->bytes_used); TRACE("Block size %d\n", msblk->block_size); TRACE("Number of inodes %d\n", msblk->inodes); - TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments)); + TRACE("Number of fragments %d\n", msblk->fragments); TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids)); TRACE("sblk->inode_table_start %llx\n", msblk->inode_table); TRACE("sblk->directory_table_start %llx\n", msblk->directory_table); @@ -273,7 +274,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_export_op = &squashfs_export_ops; handle_fragments: - fragments = le32_to_cpu(sblk->fragments); + fragments = msblk->fragments; if (fragments == 0) goto check_directory_table; From a64e47ee1fa0d9fd506ad84fedba380381965ae5 Mon Sep 17 00:00:00 2001 From: Anton Vasilyev Date: Fri, 27 Jul 2018 18:50:42 +0300 Subject: [PATCH 213/392] can: ems_usb: Fix memory leak on ems_usb_disconnect() commit 72c05f32f4a5055c9c8fe889bb6903ec959c0aad upstream. ems_usb_probe() allocates memory for dev->tx_msg_buffer, but there is no its deallocation in ems_usb_disconnect(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Anton Vasilyev Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/usb/ems_usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index b1ca40552a84..2af6e3c8b718 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -1083,6 +1083,7 @@ static void ems_usb_disconnect(struct usb_interface *intf) usb_free_urb(dev->intr_urb); kfree(dev->intr_in_buffer); + kfree(dev->tx_msg_buffer); } } From c4682ea443b921c88d6b6165619d6ab973fe41c1 Mon Sep 17 00:00:00 2001 From: Jiang Biao Date: Wed, 18 Jul 2018 10:29:28 +0800 Subject: [PATCH 214/392] virtio_balloon: fix another race between migration and ballooning commit 89da619bc18d79bca5304724c11d4ba3b67ce2c6 upstream. Kernel panic when with high memory pressure, calltrace looks like, PID: 21439 TASK: ffff881be3afedd0 CPU: 16 COMMAND: "java" #0 [ffff881ec7ed7630] machine_kexec at ffffffff81059beb #1 [ffff881ec7ed7690] __crash_kexec at ffffffff81105942 #2 [ffff881ec7ed7760] crash_kexec at ffffffff81105a30 #3 [ffff881ec7ed7778] oops_end at ffffffff816902c8 #4 [ffff881ec7ed77a0] no_context at ffffffff8167ff46 #5 [ffff881ec7ed77f0] __bad_area_nosemaphore at ffffffff8167ffdc #6 [ffff881ec7ed7838] __node_set at ffffffff81680300 #7 [ffff881ec7ed7860] __do_page_fault at ffffffff8169320f #8 [ffff881ec7ed78c0] do_page_fault at ffffffff816932b5 #9 [ffff881ec7ed78f0] page_fault at ffffffff8168f4c8 [exception RIP: _raw_spin_lock_irqsave+47] RIP: ffffffff8168edef RSP: ffff881ec7ed79a8 RFLAGS: 00010046 RAX: 0000000000000246 RBX: ffffea0019740d00 RCX: ffff881ec7ed7fd8 RDX: 0000000000020000 RSI: 0000000000000016 RDI: 0000000000000008 RBP: ffff881ec7ed79a8 R8: 0000000000000246 R9: 000000000001a098 R10: ffff88107ffda000 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000008 R14: ffff881ec7ed7a80 R15: ffff881be3afedd0 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 It happens in the pagefault and results in double pagefault during compacting pages when memory allocation fails. Analysed the vmcore, the page leads to second pagefault is corrupted with _mapcount=-256, but private=0. It's caused by the race between migration and ballooning, and lock missing in virtballoon_migratepage() of virtio_balloon driver. This patch fix the bug. Fixes: e22504296d4f64f ("virtio_balloon: introduce migration primitives to balloon pages") Cc: stable@vger.kernel.org Signed-off-by: Jiang Biao Signed-off-by: Huang Chong Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/virtio/virtio_balloon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 771d9e76fcc1..5bad60a6dadd 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -416,7 +416,9 @@ static int virtballoon_migratepage(struct balloon_dev_info *vb_dev_info, tell_host(vb, vb->inflate_vq); /* balloon's page migration 2nd step -- deflate "page" */ + spin_lock_irqsave(&vb_dev_info->pages_lock, flags); balloon_page_delete(page); + spin_unlock_irqrestore(&vb_dev_info->pages_lock, flags); vb->num_pfns = VIRTIO_BALLOON_PAGES_PER_PAGE; set_page_pfns(vb->pfns, page); tell_host(vb, vb->deflate_vq); From fc7ec0c4ef5c29fc0679e12a02e22869b3092370 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 13 Jul 2018 16:12:32 +0800 Subject: [PATCH 215/392] crypto: padlock-aes - Fix Nano workaround data corruption commit 46d8c4b28652d35dc6cfb5adf7f54e102fc04384 upstream. This was detected by the self-test thanks to Ard's chunking patch. I finally got around to testing this out on my ancient Via box. It turns out that the workaround got the assembly wrong and we end up doing count + initial cycles of the loop instead of just count. This obviously causes corruption, either by overwriting the source that is yet to be processed, or writing over the end of the buffer. On CPUs that don't require the workaround only ECB is affected. On Nano CPUs both ECB and CBC are affected. This patch fixes it by doing the subtraction prior to the assembly. Fixes: a76c1c23d0c3 ("crypto: padlock-aes - work around Nano CPU...") Cc: Reported-by: Jamie Heilman Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/padlock-aes.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index c178ed8c3908..2250db026198 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -266,6 +266,8 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, return; } + count -= initial; + if (initial) asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output) @@ -273,7 +275,7 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output) - : "d"(control_word), "b"(key), "c"(count - initial)); + : "d"(control_word), "b"(key), "c"(count)); } static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, @@ -284,6 +286,8 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, if (count < cbc_fetch_blocks) return cbc_crypt(input, output, key, iv, control_word, count); + count -= initial; + if (initial) asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ : "+S" (input), "+D" (output), "+a" (iv) @@ -291,7 +295,7 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ : "+S" (input), "+D" (output), "+a" (iv) - : "d" (control_word), "b" (key), "c" (count-initial)); + : "d" (control_word), "b" (key), "c" (count)); return iv; } From f42178c0f2f09d6e87b0a35dff3c8484eeaaa197 Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Thu, 12 Jul 2018 16:30:45 -0400 Subject: [PATCH 216/392] scsi: sg: fix minor memory leak in error path commit c170e5a8d222537e98aa8d4fddb667ff7a2ee114 upstream. Fix a minor memory leak when there is an error opening a /dev/sg device. Fixes: cc833acbee9d ("sg: O_EXCL and other lock handling") Cc: Reviewed-by: Ewan D. Milne Signed-off-by: Tony Battersby Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index a686bc922e24..074ab0d480db 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2242,6 +2242,7 @@ sg_add_sfp(Sg_device * sdp) write_lock_irqsave(&sdp->sfd_lock, iflags); if (atomic_read(&sdp->detaching)) { write_unlock_irqrestore(&sdp->sfd_lock, iflags); + kfree(sfp); return ERR_PTR(-ENODEV); } list_add_tail(&sfp->sfd_siblings, &sdp->sfds); From 2de35a8aac3f627a900cf4d259511860f83bb5a3 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Wed, 18 Jul 2018 14:29:54 -0700 Subject: [PATCH 217/392] scsi: qla2xxx: Fix ISP recovery on unload commit b08abbd9f5996309f021684f9ca74da30dcca36a upstream. During unload process, the chip can encounter problem where a FW dump would be captured. For this case, the full reset sequence will be skip to bring the chip back to full operational state. Fixes: e315cd28b9ef ("[SCSI] qla2xxx: Code changes for qla data structure refactoring") Cc: Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_os.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 26223ff51e66..7bc28c8d2832 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -5000,8 +5000,9 @@ qla2x00_do_dpc(void *data) } } - if (test_and_clear_bit(ISP_ABORT_NEEDED, - &base_vha->dpc_flags)) { + if (test_and_clear_bit + (ISP_ABORT_NEEDED, &base_vha->dpc_flags) && + !test_bit(UNLOADING, &base_vha->dpc_flags)) { ql_dbg(ql_dbg_dpc, base_vha, 0x4007, "ISP abort scheduled.\n"); From fa4bbed870c492b899cd779c05f8714c1b205e12 Mon Sep 17 00:00:00 2001 From: Anil Gurumurthy Date: Wed, 18 Jul 2018 14:29:55 -0700 Subject: [PATCH 218/392] scsi: qla2xxx: Return error when TMF returns commit b4146c4929ef61d5afca011474d59d0918a0cd82 upstream. Propagate the task management completion status properly to avoid unnecessary waits for commands to complete. Fixes: faef62d13463 ("[SCSI] qla2xxx: Fix Task Management command asynchronous handling") Cc: Signed-off-by: Anil Gurumurthy Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_init.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 99bdccf92136..6191c300faff 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -325,11 +325,10 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, wait_for_completion(&tm_iocb->u.tmf.comp); - rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ? - QLA_SUCCESS : QLA_FUNCTION_FAILED; + rval = tm_iocb->u.tmf.data; - if ((rval != QLA_SUCCESS) || tm_iocb->u.tmf.data) { - ql_dbg(ql_dbg_taskm, vha, 0x8030, + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x8030, "TM IOCB failed (%x).\n", rval); } From fed22131f5b2740acbf184910133179b558aecc0 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 14 Jul 2018 01:28:15 +0900 Subject: [PATCH 219/392] ring_buffer: tracing: Inherit the tracing setting to next ring buffer commit 73c8d8945505acdcbae137c2e00a1232e0be709f upstream. Maintain the tracing on/off setting of the ring_buffer when switching to the trace buffer snapshot. Taking a snapshot is done by swapping the backup ring buffer (max_tr_buffer). But since the tracing on/off setting is defined by the ring buffer, when swapping it, the tracing on/off setting can also be changed. This causes a strange result like below: /sys/kernel/debug/tracing # cat tracing_on 1 /sys/kernel/debug/tracing # echo 0 > tracing_on /sys/kernel/debug/tracing # cat tracing_on 0 /sys/kernel/debug/tracing # echo 1 > snapshot /sys/kernel/debug/tracing # cat tracing_on 1 /sys/kernel/debug/tracing # echo 1 > snapshot /sys/kernel/debug/tracing # cat tracing_on 0 We don't touch tracing_on, but snapshot changes tracing_on setting each time. This is an anomaly, because user doesn't know that each "ring_buffer" stores its own tracing-enable state and the snapshot is done by swapping ring buffers. Link: http://lkml.kernel.org/r/153149929558.11274.11730609978254724394.stgit@devbox Cc: Ingo Molnar Cc: Shuah Khan Cc: Tom Zanussi Cc: Hiraku Toyooka Cc: stable@vger.kernel.org Fixes: debdd57f5145 ("tracing: Make a snapshot feature available from userspace") Signed-off-by: Masami Hiramatsu [ Updated commit log and comment in the code ] Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- include/linux/ring_buffer.h | 1 + kernel/trace/ring_buffer.c | 16 ++++++++++++++++ kernel/trace/trace.c | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index e2c13cd863bd..4daa5069cbdb 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h @@ -162,6 +162,7 @@ void ring_buffer_record_enable(struct ring_buffer *buffer); void ring_buffer_record_off(struct ring_buffer *buffer); void ring_buffer_record_on(struct ring_buffer *buffer); int ring_buffer_record_is_on(struct ring_buffer *buffer); +int ring_buffer_record_is_set_on(struct ring_buffer *buffer); void ring_buffer_record_disable_cpu(struct ring_buffer *buffer, int cpu); void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu); diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 68fcf6829bc5..5821def0b7a0 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -3152,6 +3152,22 @@ int ring_buffer_record_is_on(struct ring_buffer *buffer) return !atomic_read(&buffer->record_disabled); } +/** + * ring_buffer_record_is_set_on - return true if the ring buffer is set writable + * @buffer: The ring buffer to see if write is set enabled + * + * Returns true if the ring buffer is set writable by ring_buffer_record_on(). + * Note that this does NOT mean it is in a writable state. + * + * It may return true when the ring buffer has been disabled by + * ring_buffer_record_disable(), as that is a temporary disabling of + * the ring buffer. + */ +int ring_buffer_record_is_set_on(struct ring_buffer *buffer) +{ + return !(atomic_read(&buffer->record_disabled) & RB_BUFFER_OFF); +} + /** * ring_buffer_record_disable_cpu - stop all writes into the cpu_buffer * @buffer: The ring buffer to stop writes to. diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index c8717cde9249..f5f18f398ce9 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1023,6 +1023,12 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) arch_spin_lock(&tr->max_lock); + /* Inherit the recordable setting from trace_buffer */ + if (ring_buffer_record_is_set_on(tr->trace_buffer.buffer)) + ring_buffer_record_on(tr->max_buffer.buffer); + else + ring_buffer_record_off(tr->max_buffer.buffer); + buf = tr->trace_buffer.buffer; tr->trace_buffer.buffer = tr->max_buffer.buffer; tr->max_buffer.buffer = buf; From 31430f2b98f6053933482e51d008124fc31bc3e0 Mon Sep 17 00:00:00 2001 From: Shankara Pailoor Date: Tue, 5 Jun 2018 08:33:27 -0500 Subject: [PATCH 220/392] jfs: Fix inconsistency between memory allocation and ea_buf->max_size commit 92d34134193e5b129dc24f8d79cb9196626e8d7a upstream. The code is assuming the buffer is max_size length, but we weren't allocating enough space for it. Signed-off-by: Shankara Pailoor Signed-off-by: Dave Kleikamp Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- fs/jfs/xattr.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 46325d5c34fc..405e8c42cb1a 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -493,15 +493,17 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size) if (size > PSIZE) { /* * To keep the rest of the code simple. Allocate a - * contiguous buffer to work with + * contiguous buffer to work with. Make the buffer large + * enough to make use of the whole extent. */ - ea_buf->xattr = kmalloc(size, GFP_KERNEL); + ea_buf->max_size = (size + sb->s_blocksize - 1) & + ~(sb->s_blocksize - 1); + + ea_buf->xattr = kmalloc(ea_buf->max_size, GFP_KERNEL); if (ea_buf->xattr == NULL) return -ENOMEM; ea_buf->flag = EA_MALLOC; - ea_buf->max_size = (size + sb->s_blocksize - 1) & - ~(sb->s_blocksize - 1); if (ea_size == 0) return 0; From 830f9674e76d08d04585e53fc200ae8af99966e7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 9 Aug 2018 12:20:36 +0200 Subject: [PATCH 221/392] Linux 3.18.118 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9c894e7e586d..5c3464b5bb1e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 18 -SUBLEVEL = 117 +SUBLEVEL = 118 EXTRAVERSION = NAME = Diseased Newt From 40579edcf943613bdd717c1e97dbe8be76ebaa57 Mon Sep 17 00:00:00 2001 From: engstk Date: Sat, 27 Aug 2016 05:59:29 +0100 Subject: [PATCH 222/392] drivers: misc: implement usb fast charge mode echo 0 /sys/kernel/fast_charge/force_fast_charge (disable) echo 1 /sys/kernel/fast_charge/force_fast_charge (enable) Signed-off-by: engstk Signed-off-by: Francisco Franco --- drivers/misc/Kconfig | 7 +++ drivers/misc/Makefile | 1 + drivers/misc/fastchg.c | 102 ++++++++++++++++++++++++++++++++ drivers/power/qpnp-smbcharger.c | 9 +++ include/linux/fastchg.h | 22 +++++++ 5 files changed, 141 insertions(+) create mode 100644 drivers/misc/fastchg.c create mode 100644 include/linux/fastchg.h diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 80ed8a3b81b0..8e7d82ce1eb9 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -643,6 +643,13 @@ config MEMORY_STATE_TIME help Memory time statistics exported to /sys/kernel/memory_state_time + +config FORCE_FAST_CHARGE + bool "Force faster charge rate for USB" + default n + help + This allows users to override default charge rate for USB + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 2ebaa0c98532..2b7ca8226ae7 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -84,3 +84,4 @@ obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o obj-$(CONFIG_APDS9930) += apds993x.o obj-$(CONFIG_UID_SYS_STATS) += uid_sys_stats.o obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o +obj-$(CONFIG_FORCE_FAST_CHARGE) += fastchg.o diff --git a/drivers/misc/fastchg.c b/drivers/misc/fastchg.c new file mode 100644 index 000000000000..a00d425bb57d --- /dev/null +++ b/drivers/misc/fastchg.c @@ -0,0 +1,102 @@ +/* + * Author: Chad Froebel + * + * Port to Thulium: engstk + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Possible values for "force_fast_charge" are : + * + * 0 - Disabled (default) + * 1 - Force faster charge +*/ + +#include +#include +#include +#include + +int force_fast_charge = 0; + +static int __init get_fastcharge_opt(char *ffc) +{ + if (strcmp(ffc, "0") == 0) { + force_fast_charge = 0; + } else if (strcmp(ffc, "1") == 0) { + force_fast_charge = 1; + } else { + force_fast_charge = 0; + } + return 1; +} + +__setup("ffc=", get_fastcharge_opt); + +static ssize_t force_fast_charge_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + size_t count = 0; + count += sprintf(buf, "%d\n", force_fast_charge); + return count; +} + +static ssize_t force_fast_charge_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + sscanf(buf, "%d ", &force_fast_charge); + if (force_fast_charge < 0 || force_fast_charge > 1) + force_fast_charge = 0; + + return count; +} + +static struct kobj_attribute force_fast_charge_attribute = +__ATTR(force_fast_charge, 0664, force_fast_charge_show, force_fast_charge_store); + +static struct attribute *force_fast_charge_attrs[] = { +&force_fast_charge_attribute.attr, +NULL, +}; + +static struct attribute_group force_fast_charge_attr_group = { +.attrs = force_fast_charge_attrs, +}; + +/* Initialize fast charge sysfs folder */ +static struct kobject *force_fast_charge_kobj; + +int force_fast_charge_init(void) +{ + int force_fast_charge_retval; + + force_fast_charge_kobj = kobject_create_and_add("fast_charge", kernel_kobj); + if (!force_fast_charge_kobj) { + return -ENOMEM; + } + + force_fast_charge_retval = sysfs_create_group(force_fast_charge_kobj, &force_fast_charge_attr_group); + + if (force_fast_charge_retval) + kobject_put(force_fast_charge_kobj); + + if (force_fast_charge_retval) + kobject_put(force_fast_charge_kobj); + + return (force_fast_charge_retval); +} + +void force_fast_charge_exit(void) +{ + kobject_put(force_fast_charge_kobj); +} + +module_init(force_fast_charge_init); +module_exit(force_fast_charge_exit); diff --git a/drivers/power/qpnp-smbcharger.c b/drivers/power/qpnp-smbcharger.c index 546581c80688..03cb261ec855 100644 --- a/drivers/power/qpnp-smbcharger.c +++ b/drivers/power/qpnp-smbcharger.c @@ -43,6 +43,11 @@ #include #include #include + +#ifdef CONFIG_FORCE_FAST_CHARGE +#include +#endif + #if defined(CONFIG_FB) #include #include @@ -2099,7 +2104,11 @@ static int smbchg_set_usb_current_max(struct smbchg_chip *chip, } chip->usb_max_current_ma = 500; } +#ifdef CONFIG_FORCE_FAST_CHARGE + if ((force_fast_charge > 0 && current_ma == CURRENT_500_MA) || current_ma == CURRENT_900_MA) { +#else if (current_ma == CURRENT_900_MA) { +#endif rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, CFG_USB_2_3_SEL_BIT, CFG_USB_3); diff --git a/include/linux/fastchg.h b/include/linux/fastchg.h new file mode 100644 index 000000000000..9dc0adb63d75 --- /dev/null +++ b/include/linux/fastchg.h @@ -0,0 +1,22 @@ +/* + * Author: Chad Froebel + * + * Port to Thulium: engstk + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_FASTCHG_H +#define _LINUX_FASTCHG_H + +extern int force_fast_charge; + +#endif From 1a86992f9d14ab22220cdc50b2f505fc8db1db57 Mon Sep 17 00:00:00 2001 From: joshuous Date: Sat, 11 Aug 2018 04:41:58 -0400 Subject: [PATCH 223/392] defconfig: Enable FORCE_FAST_CHARGE Config is disabled by default. Signed-off-by: joshuous --- arch/arm64/configs/msm-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig index 3106c09e7ebd..e3cec69b09f4 100644 --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm64/configs/msm-perf_defconfig @@ -250,6 +250,7 @@ CONFIG_TUSB320_TYPE_C=y CONFIG_FUSB301_TYPE_C=y CONFIG_PTN5150_TYPE_C=y CONFIG_TI_DRV2667=y +CONFIG_FORCE_FAST_CHARGE=y CONFIG_EEPROM_AT24=y CONFIG_DTS_EAGLE=y CONFIG_SCSI=y From 5e4b35daafa3b0f1ec37c88a5e7a93a7efa4c6f0 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 16 Aug 2018 03:01:42 -0700 Subject: [PATCH 224/392] sched: qhmp_core: Fix build errors The changes in commit 03420c696efa ("sched: Add commits left out during CAF's 3.18 stable merge") should have been applied to this file as well, otherwise there will be build errors with CONFIG_SCHED_QHMP enabled as it replaces the entire scheduling core with the qhmp_* files. ../kernel/sched/qhmp_core.c:6269:14: error: redefinition of 'io_schedule' Build tested with msm8937-perf_defconfig. Closes: #6 Reported-by: Shoaib0597 Signed-off-by: Nathan Chancellor --- kernel/sched/qhmp_core.c | 49 ++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/kernel/sched/qhmp_core.c b/kernel/sched/qhmp_core.c index ce2c0c3dc1a1..b3ea4153f2e9 100644 --- a/kernel/sched/qhmp_core.c +++ b/kernel/sched/qhmp_core.c @@ -6266,34 +6266,23 @@ EXPORT_SYMBOL_GPL(yield_to); * This task is about to go to sleep on IO. Increment rq->nr_iowait so * that process accounting knows that this is a task in IO wait state. */ -void __sched io_schedule(void) -{ - struct rq *rq = raw_rq(); - - delayacct_blkio_start(); - atomic_inc(&rq->nr_iowait); - blk_flush_plug(current); - current->in_iowait = 1; - schedule(); - current->in_iowait = 0; - atomic_dec(&rq->nr_iowait); - delayacct_blkio_end(); -} -EXPORT_SYMBOL(io_schedule); - long __sched io_schedule_timeout(long timeout) { - struct rq *rq = raw_rq(); + int old_iowait = current->in_iowait; + struct rq *rq; long ret; + current->in_iowait = 1; + blk_schedule_flush_plug(current); + delayacct_blkio_start(); + rq = raw_rq(); atomic_inc(&rq->nr_iowait); - blk_flush_plug(current); - current->in_iowait = 1; ret = schedule_timeout(timeout); - current->in_iowait = 0; + current->in_iowait = old_iowait; atomic_dec(&rq->nr_iowait); delayacct_blkio_end(); + return ret; } EXPORT_SYMBOL(io_schedule_timeout); @@ -7722,6 +7711,9 @@ enum s_alloc { * Build an iteration mask that can exclude certain CPUs from the upwards * domain traversal. * + * Only CPUs that can arrive at this group should be considered to continue + * balancing. + * * Asymmetric node setups can result in situations where the domain tree is of * unequal depth, make sure to skip domains that already cover the entire * range. @@ -7733,18 +7725,31 @@ enum s_alloc { */ static void build_group_mask(struct sched_domain *sd, struct sched_group *sg) { - const struct cpumask *span = sched_domain_span(sd); + const struct cpumask *sg_span = sched_group_cpus(sg); struct sd_data *sdd = sd->private; struct sched_domain *sibling; int i; - for_each_cpu(i, span) { + for_each_cpu(i, sg_span) { sibling = *per_cpu_ptr(sdd->sd, i); - if (!cpumask_test_cpu(i, sched_domain_span(sibling))) + + /* + * Can happen in the asymmetric case, where these siblings are + * unused. The mask will not be empty because those CPUs that + * do have the top domain _should_ span the domain. + */ + if (!sibling->child) + continue; + + /* If we would not end up here, we can't continue from here */ + if (!cpumask_equal(sg_span, sched_domain_span(sibling->child))) continue; cpumask_set_cpu(i, sched_group_mask(sg)); } + + /* We must not have empty masks here */ + WARN_ON_ONCE(cpumask_empty(sched_group_mask(sg))); } /* From a321a5c56e185856471b1358da9638517d2c8b03 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 16 Aug 2018 03:17:18 -0700 Subject: [PATCH 225/392] sched: qhmp_core: Apply missing commits Unfortunately, it's come to my attention that with CONFIG_SCHED_QHMP enabled, the entire scheduling core is duplicated. This is pretty horrendous but just something I'll have to live with. This commit applies the kernel/sched/{core.c,rt.c} commits missing between LA.UM.6.6.r1-09400-89xx.0 and 3.18.118: 1c3a4e61b11d ("sched: Make resched_cpu() unconditional") 26b34205542d ("sched: Stop resched_cpu() from sending IPIs to offline CPUs") e42acd54ef45 ("sched/rt: Fix rq->clock_update_flags < RQCF_ACT_SKIP warning") Signed-off-by: Nathan Chancellor --- kernel/sched/qhmp_core.c | 6 +++--- kernel/sched/qhmp_rt.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/kernel/sched/qhmp_core.c b/kernel/sched/qhmp_core.c index b3ea4153f2e9..554eff8040c2 100644 --- a/kernel/sched/qhmp_core.c +++ b/kernel/sched/qhmp_core.c @@ -641,9 +641,9 @@ void resched_cpu(int cpu) struct rq *rq = cpu_rq(cpu); unsigned long flags; - if (!raw_spin_trylock_irqsave(&rq->lock, flags)) - return; - resched_curr(rq); + raw_spin_lock_irqsave(&rq->lock, flags); + if (cpu_online(cpu) || cpu == smp_processor_id()) + resched_curr(rq); raw_spin_unlock_irqrestore(&rq->lock, flags); } diff --git a/kernel/sched/qhmp_rt.c b/kernel/sched/qhmp_rt.c index 201cadeca153..cc464c4e82de 100644 --- a/kernel/sched/qhmp_rt.c +++ b/kernel/sched/qhmp_rt.c @@ -819,6 +819,8 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun) struct rq *rq = rq_of_rt_rq(rt_rq); raw_spin_lock(&rq->lock); + update_rq_clock(rq); + if (rt_rq->rt_time) { u64 runtime; From 38b901473177ece7e8c34eaa551b76b49774c4bc Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Thu, 9 Aug 2018 16:42:16 +0200 Subject: [PATCH 226/392] xen/netfront: don't cache skb_shinfo() commit d472b3a6cf63cd31cae1ed61930f07e6cd6671b5 upstream. skb_shinfo() can change when calling __pskb_pull_tail(): Don't cache its return value. Cc: stable@vger.kernel.org Signed-off-by: Juergen Gross Reviewed-by: Wei Liu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netfront.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 584d035ec0dd..b780c059cc03 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -903,7 +903,6 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue, struct sk_buff *skb, struct sk_buff_head *list) { - struct skb_shared_info *shinfo = skb_shinfo(skb); RING_IDX cons = queue->rx.rsp_cons; struct sk_buff *nskb; @@ -912,15 +911,16 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue, RING_GET_RESPONSE(&queue->rx, ++cons); skb_frag_t *nfrag = &skb_shinfo(nskb)->frags[0]; - if (shinfo->nr_frags == MAX_SKB_FRAGS) { + if (skb_shinfo(skb)->nr_frags == MAX_SKB_FRAGS) { unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to; BUG_ON(pull_to <= skb_headlen(skb)); __pskb_pull_tail(skb, pull_to - skb_headlen(skb)); } - BUG_ON(shinfo->nr_frags >= MAX_SKB_FRAGS); + BUG_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS); - skb_add_rx_frag(skb, shinfo->nr_frags, skb_frag_page(nfrag), + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + skb_frag_page(nfrag), rx->offset, rx->status, PAGE_SIZE); skb_shinfo(nskb)->nr_frags = 0; From 7f48b39f2437fc159b818aac85ffef35521e5709 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Aug 2018 09:03:58 -0400 Subject: [PATCH 227/392] root dentries need RCU-delayed freeing commit 90bad5e05bcdb0308cfa3d3a60f5c0b9c8e2efb3 upstream. Since mountpoint crossing can happen without leaving lazy mode, root dentries do need the same protection against having their memory freed without RCU delay as everything else in the tree. It's partially hidden by RCU delay between detaching from the mount tree and dropping the vfsmount reference, but the starting point of pathwalk can be on an already detached mount, in which case umount-caused RCU delay has already passed by the time the lazy pathwalk grabs rcu_read_lock(). If the starting point happens to be at the root of that vfsmount *and* that vfsmount covers the entire filesystem, we get trouble. Fixes: 48a066e72d97 ("RCU'd vsfmounts") Cc: stable@vger.kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/dcache.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index a34d4019f465..5977fc3f4705 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1848,10 +1848,12 @@ struct dentry *d_make_root(struct inode *root_inode) static const struct qstr name = QSTR_INIT("/", 1); res = __d_alloc(root_inode->i_sb, &name); - if (res) + if (res) { + res->d_flags |= DCACHE_RCUACCESS; d_instantiate(res, root_inode); - else + } else { iput(root_inode); + } } return res; } From 6f4d6842ea3716b8b9bc8f470ea217670b03d8bc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 9 Aug 2018 17:21:17 -0400 Subject: [PATCH 228/392] fix mntput/mntput race commit 9ea0a46ca2c318fcc449c1e6b62a7230a17888f1 upstream. mntput_no_expire() does the calculation of total refcount under mount_lock; unfortunately, the decrement (as well as all increments) are done outside of it, leading to false positives in the "are we dropping the last reference" test. Consider the following situation: * mnt is a lazy-umounted mount, kept alive by two opened files. One of those files gets closed. Total refcount of mnt is 2. On CPU 42 mntput(mnt) (called from __fput()) drops one reference, decrementing component * After it has looked at component #0, the process on CPU 0 does mntget(), incrementing component #0, gets preempted and gets to run again - on CPU 69. There it does mntput(), which drops the reference (component #69) and proceeds to spin on mount_lock. * On CPU 42 our first mntput() finishes counting. It observes the decrement of component #69, but not the increment of component #0. As the result, the total it gets is not 1 as it should've been - it's 0. At which point we decide that vfsmount needs to be killed and proceed to free it and shut the filesystem down. However, there's still another opened file on that filesystem, with reference to (now freed) vfsmount, etc. and we are screwed. It's not a wide race, but it can be reproduced with artificial slowdown of the mnt_get_count() loop, and it should be easier to hit on SMP KVM setups. Fix consists of moving the refcount decrement under mount_lock; the tricky part is that we want (and can) keep the fast case (i.e. mount that still has non-NULL ->mnt_ns) entirely out of mount_lock. All places that zero mnt->mnt_ns are dropping some reference to mnt and they call synchronize_rcu() before that mntput(). IOW, if mntput() observes (under rcu_read_lock()) a non-NULL ->mnt_ns, it is guaranteed that there is another reference yet to be dropped. Reported-by: Jann Horn Tested-by: Jann Horn Fixes: 48a066e72d97 ("RCU'd vsfmounts") Cc: stable@vger.kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/namespace.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index ded3f1edd7f7..2472083e0487 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1049,12 +1049,22 @@ static DECLARE_DELAYED_WORK(delayed_mntput_work, delayed_mntput); static void mntput_no_expire(struct mount *mnt) { rcu_read_lock(); - mnt_add_count(mnt, -1); - if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */ + if (likely(READ_ONCE(mnt->mnt_ns))) { + /* + * Since we don't do lock_mount_hash() here, + * ->mnt_ns can change under us. However, if it's + * non-NULL, then there's a reference that won't + * be dropped until after an RCU delay done after + * turning ->mnt_ns NULL. So if we observe it + * non-NULL under rcu_read_lock(), the reference + * we are dropping is not the final one. + */ + mnt_add_count(mnt, -1); rcu_read_unlock(); return; } lock_mount_hash(); + mnt_add_count(mnt, -1); if (mnt_get_count(mnt)) { rcu_read_unlock(); unlock_mount_hash(); From 4111fe47e3fe2e30dceb3e15b2cf696eb94618b7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 9 Aug 2018 17:51:32 -0400 Subject: [PATCH 229/392] fix __legitimize_mnt()/mntput() race commit 119e1ef80ecfe0d1deb6378d4ab41f5b71519de1 upstream. __legitimize_mnt() has two problems - one is that in case of success the check of mount_lock is not ordered wrt preceding increment of refcount, making it possible to have successful __legitimize_mnt() on one CPU just before the otherwise final mntpu() on another, with __legitimize_mnt() not seeing mntput() taking the lock and mntput() not seeing the increment done by __legitimize_mnt(). Solved by a pair of barriers. Another is that failure of __legitimize_mnt() on the second read_seqretry() leaves us with reference that'll need to be dropped by caller; however, if that races with final mntput() we can end up with caller dropping rcu_read_lock() and doing mntput() to release that reference - with the first mntput() having freed the damn thing just as rcu_read_lock() had been dropped. Solution: in "do mntput() yourself" failure case grab mount_lock, check if MNT_DOOMED has been set by racing final mntput() that has missed our increment and if it has - undo the increment and treat that as "failure, caller doesn't need to drop anything" case. It's not easy to hit - the final mntput() has to come right after the first read_seqretry() in __legitimize_mnt() *and* manage to miss the increment done by __legitimize_mnt() before the second read_seqretry() in there. The things that are almost impossible to hit on bare hardware are not impossible on SMP KVM, though... Reported-by: Oleg Nesterov Fixes: 48a066e72d97 ("RCU'd vsfmounts") Cc: stable@vger.kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/namespace.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fs/namespace.c b/fs/namespace.c index 2472083e0487..df76ec5f22cb 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -590,12 +590,21 @@ bool legitimize_mnt(struct vfsmount *bastard, unsigned seq) return true; mnt = real_mount(bastard); mnt_add_count(mnt, 1); + smp_mb(); // see mntput_no_expire() if (likely(!read_seqretry(&mount_lock, seq))) return true; if (bastard->mnt_flags & MNT_SYNC_UMOUNT) { mnt_add_count(mnt, -1); return false; } + lock_mount_hash(); + if (unlikely(bastard->mnt_flags & MNT_DOOMED)) { + mnt_add_count(mnt, -1); + unlock_mount_hash(); + return true; + } + unlock_mount_hash(); + rcu_read_unlock(); mntput(bastard); rcu_read_lock(); @@ -1064,6 +1073,11 @@ static void mntput_no_expire(struct mount *mnt) return; } lock_mount_hash(); + /* + * make sure that if __legitimize_mnt() has not seen us grab + * mount_lock, we'll see their refcount increment here. + */ + smp_mb(); mnt_add_count(mnt, -1); if (mnt_get_count(mnt)) { rcu_read_unlock(); From af773a647f6cae37658a3e235b08a417960d36a8 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 15 Jun 2018 09:41:29 +0200 Subject: [PATCH 230/392] ARM: dts: imx6sx: fix irq for pcie bridge commit 1bcfe0564044be578841744faea1c2f46adc8178 upstream. Use the correct IRQ line for the MSI controller in the PCIe host controller. Apparently a different IRQ line is used compared to other i.MX6 variants. Without this change MSI IRQs aren't properly propagated to the upstream interrupt controller. Signed-off-by: Oleksij Rempel Reviewed-by: Lucas Stach Fixes: b1d17f68e5c5 ("ARM: dts: imx: add initial imx6sx device tree source") Signed-off-by: Shawn Guo Signed-off-by: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/imx6sx.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi index f3e88c03b1e4..a7c011f1edde 100644 --- a/arch/arm/boot/dts/imx6sx.dtsi +++ b/arch/arm/boot/dts/imx6sx.dtsi @@ -1202,7 +1202,7 @@ /* non-prefetchable memory */ 0x82000000 0 0x08000000 0x08000000 0 0x00f00000>; num-lanes = <1>; - interrupts = ; + interrupts = ; clocks = <&clks IMX6SX_CLK_PCIE_REF_125M>, <&clks IMX6SX_CLK_PCIE_AXI>, <&clks IMX6SX_CLK_LVDS1_OUT>, From 208255c7a3bfdb4e7a02d1aba8c4c68affd9027e Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 28 Apr 2018 21:37:03 +0900 Subject: [PATCH 231/392] kprobes/x86: Fix %p uses in error messages commit 0ea063306eecf300fcf06d2f5917474b580f666f upstream. Remove all %p uses in error messages in kprobes/x86. Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Anil S Keshavamurthy Cc: Arnd Bergmann Cc: David Howells Cc: David S . Miller Cc: Heiko Carstens Cc: Jon Medhurst Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Thomas Richter Cc: Tobin C . Harding Cc: Will Deacon Cc: acme@kernel.org Cc: akpm@linux-foundation.org Cc: brueckner@linux.vnet.ibm.com Cc: linux-arch@vger.kernel.org Cc: rostedt@goodmis.org Cc: schwidefsky@de.ibm.com Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/lkml/152491902310.9916.13355297638917767319.stgit@devbox Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/kprobes/core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 51947348fcb9..323d122267b2 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -365,7 +365,6 @@ int __copy_instruction(u8 *dest, u8 *src) newdisp = (u8 *) src + (s64) insn.displacement.value - (u8 *) dest; if ((s64) (s32) newdisp != newdisp) { pr_err("Kprobes error: new displacement does not fit into s32 (%llx)\n", newdisp); - pr_err("\tSrc: %p, Dest: %p, old disp: %x\n", src, dest, insn.displacement.value); return 0; } disp = (u8 *) dest + insn_offset_displacement(&insn); @@ -568,8 +567,7 @@ static int reenter_kprobe(struct kprobe *p, struct pt_regs *regs, * Raise a BUG or we'll continue in an endless reentering loop * and eventually a stack overflow. */ - printk(KERN_WARNING "Unrecoverable kprobe detected at %p.\n", - p->addr); + pr_err("Unrecoverable kprobe detected.\n"); dump_kprobe(p); BUG(); default: From 84d2099e70072468af1f565853f8958d9e12e3fd Mon Sep 17 00:00:00 2001 From: Erick Reyes Date: Wed, 15 Aug 2018 17:55:48 -0700 Subject: [PATCH 232/392] ALSA: info: Check for integer overflow in snd_info_entry_write() Commit 4adb7bcbcb69 ("ALSA: core: Use seq_file for text proc file reads") heavily refactored ALSA procfs and fixed the overflow as a side-effect, so this fix only applies to kernels < 4.2 and there is no upstream equivalent snd_info_entry_write() resizes the buffer with an unsigned long size argument that gets truncated because resize_info_buffer() takes the size parameter as an unsigned int. On 64-bit kernels, this causes the following copy_to_user() to write out-of-bounds if (pos + count) can't be represented by an unsigned int. Signed-off-by: Siqi Lin Signed-off-by: Erick Reyes Signed-off-by: Greg Kroah-Hartman --- sound/core/info.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/core/info.c b/sound/core/info.c index 9f404e965ea2..08832c973a53 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -253,6 +253,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer struct snd_info_buffer *buf; ssize_t size = 0; loff_t pos; + unsigned long realloc_size; data = file->private_data; if (snd_BUG_ON(!data)) @@ -261,7 +262,8 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer pos = *offset; if (pos < 0 || (long) pos != pos || (ssize_t) count < 0) return -EIO; - if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos) + realloc_size = (unsigned long) pos + (unsigned long) count; + if (realloc_size < (unsigned long) pos || realloc_size > UINT_MAX) return -EIO; switch (entry->content) { case SNDRV_INFO_CONTENT_TEXT: From cdc103fb630478aa031c1b808a8e57bc734d2e36 Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Wed, 10 Dec 2014 15:42:22 -0800 Subject: [PATCH 233/392] mm: slub: fix format mismatches in slab_err() callers commit f6edde9cbe0634e4391b6e421a609ca3f57f6c38 upstream. Adding __printf(3, 4) to slab_err exposed following: mm/slub.c: In function `check_slab': mm/slub.c:852:4: warning: format `%u' expects argument of type `unsigned int', but argument 4 has type `const char *' [-Wformat=] s->name, page->objects, maxobj); ^ mm/slub.c:852:4: warning: too many arguments for format [-Wformat-extra-args] mm/slub.c:857:4: warning: format `%u' expects argument of type `unsigned int', but argument 4 has type `const char *' [-Wformat=] s->name, page->inuse, page->objects); ^ mm/slub.c:857:4: warning: too many arguments for format [-Wformat-extra-args] mm/slub.c: In function `on_freelist': mm/slub.c:905:4: warning: format `%d' expects argument of type `int', but argument 5 has type `long unsigned int' [-Wformat=] "should be %d", page->objects, max_objects); Fix first two warnings by removing redundant s->name. Fix the last by changing type of max_object from unsigned long to int. Signed-off-by: Andrey Ryabinin Cc: Christoph Lameter Cc: Pekka Enberg Acked-by: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/slub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 70a9f027f963..b3e3c8f339a0 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -849,12 +849,12 @@ static int check_slab(struct kmem_cache *s, struct page *page) maxobj = order_objects(compound_order(page), s->size, s->reserved); if (page->objects > maxobj) { slab_err(s, page, "objects %u > max %u", - s->name, page->objects, maxobj); + page->objects, maxobj); return 0; } if (page->inuse > page->objects) { slab_err(s, page, "inuse %u > max %u", - s->name, page->inuse, page->objects); + page->inuse, page->objects); return 0; } /* Slab_pad_check fixes things up after itself */ @@ -871,7 +871,7 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search) int nr = 0; void *fp; void *object = NULL; - unsigned long max_objects; + int max_objects; fp = page->freelist; while (fp && nr <= page->objects) { From 982ad049e60e54f5a1425123637b770ad3f65df6 Mon Sep 17 00:00:00 2001 From: Liwei Song Date: Tue, 13 Jun 2017 00:59:53 -0400 Subject: [PATCH 234/392] i2c: ismt: fix wrong device address when unmap the data buffer commit 17e83549e199d89aace7788a9f11c108671eecf5 upstream. Fix the following kernel bug: kernel BUG at drivers/iommu/intel-iommu.c:3260! invalid opcode: 0000 [#5] PREEMPT SMP Hardware name: Intel Corp. Harcuvar/Server, BIOS HAVLCRB0.X64.0013.D39.1608311820 08/31/2016 task: ffff880175389950 ti: ffff880176bec000 task.ti: ffff880176bec000 RIP: 0010:[] [] intel_unmap+0x25b/0x260 RSP: 0018:ffff880176bef5e8 EFLAGS: 00010296 RAX: 0000000000000024 RBX: ffff8800773c7c88 RCX: 000000000000ce04 RDX: 0000000080000000 RSI: 0000000000000000 RDI: 0000000000000009 RBP: ffff880176bef638 R08: 0000000000000010 R09: 0000000000000004 R10: ffff880175389c78 R11: 0000000000000a4f R12: ffff8800773c7868 R13: 00000000ffffac88 R14: ffff8800773c7818 R15: 0000000000000001 FS: 00007fef21258700(0000) GS:ffff88017b5c0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000000066d6d8 CR3: 000000007118c000 CR4: 00000000003406e0 Stack: 00000000ffffac88 ffffffff8199867f ffff880176bef5f8 ffff880100000030 ffff880176bef668 ffff8800773c7c88 ffff880178288098 ffff8800772c0010 ffff8800773c7818 0000000000000001 ffff880176bef648 ffffffff8150a86e Call Trace: [] ? printk+0x46/0x48 [] intel_unmap_page+0xe/0x10 [] ismt_access+0x27b/0x8fa [i2c_ismt] [] ? __pm_runtime_suspend+0xa0/0xa0 [] ? pm_suspend_timer_fn+0x80/0x80 [] ? __pm_runtime_suspend+0xa0/0xa0 [] ? pm_suspend_timer_fn+0x80/0x80 [] ? pci_bus_read_dev_vendor_id+0xf0/0xf0 [] i2c_smbus_xfer+0xec/0x4b0 [] ? vprintk_emit+0x345/0x530 [] i2cdev_ioctl_smbus+0x12b/0x240 [i2c_dev] [] ? vprintk_default+0x29/0x40 [] i2cdev_ioctl+0x63/0x1ec [i2c_dev] [] do_vfs_ioctl+0x328/0x5d0 [] ? vfs_write+0x11c/0x190 [] ? rt_up_read+0x19/0x20 [] SyS_ioctl+0x81/0xa0 [] system_call_fastpath+0x16/0x6e This happen When run "i2cdetect -y 0" detect SMBus iSMT adapter. After finished I2C block read/write, when unmap the data buffer, a wrong device address was pass to dma_unmap_single(). To fix this, give dma_unmap_single() the "dev" parameter, just like what dma_map_single() does, then unmap can find the right devices. Fixes: 13f35ac14cd0 ("i2c: Adding support for Intel iSMT SMBus 2.0 host controller") Signed-off-by: Liwei Song Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-ismt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index f771c6afbab5..beab499d182c 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -587,7 +587,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, /* unmap the data buffer */ if (dma_size != 0) - dma_unmap_single(&adap->dev, dma_addr, dma_size, dma_direction); + dma_unmap_single(dev, dma_addr, dma_size, dma_direction); if (unlikely(!ret)) { dev_err(dev, "completion wait timed out\n"); From cd635c1cb35b4d5491b137630c3bb62e3ae34969 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 1 Jul 2018 19:46:06 -0700 Subject: [PATCH 235/392] kbuild: verify that $DEPMOD is installed commit 934193a654c1f4d0643ddbf4b2529b508cae926e upstream. Verify that 'depmod' ($DEPMOD) is installed. This is a partial revert of commit 620c231c7a7f ("kbuild: do not check for ancient modutils tools"). Also update Documentation/process/changes.rst to refer to kmod instead of module-init-tools. Fixes kernel bugzilla #198965: https://bugzilla.kernel.org/show_bug.cgi?id=198965 Signed-off-by: Randy Dunlap Cc: Lucas De Marchi Cc: Lucas De Marchi Cc: Michal Marek Cc: Jessica Yu Cc: Chih-Wei Huang Cc: stable@vger.kernel.org # any kernel since 2012 Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- Documentation/Changes | 17 ++++++----------- scripts/depmod.sh | 8 +++++++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Documentation/Changes b/Documentation/Changes index 1de131bb49fb..9ad68f1819d3 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -25,7 +25,7 @@ o Gnu C 3.2 # gcc --version o Gnu make 3.80 # make --version o binutils 2.12 # ld -v o util-linux 2.10o # fdformat --version -o module-init-tools 0.9.10 # depmod -V +o kmod 13 # depmod -V o e2fsprogs 1.41.4 # e2fsck -V o jfsutils 1.1.3 # fsck.jfs -V o reiserfsprogs 3.6.3 # reiserfsck -V @@ -119,12 +119,6 @@ is not build with CONFIG_KALLSYMS and you have no way to rebuild and reproduce the Oops with that option, then you can still decode that Oops with ksymoops. -Module-Init-Tools ------------------ - -A new module loader is now in the kernel that requires module-init-tools -to use. It is backward compatible with the 2.4.x series kernels. - Mkinitrd -------- @@ -302,14 +296,15 @@ Util-linux ---------- o +Kmod +---- +o +o + Ksymoops -------- o -Module-Init-Tools ------------------ -o - Mkinitrd -------- o diff --git a/scripts/depmod.sh b/scripts/depmod.sh index 122599b1c13b..ea1e96921e3b 100755 --- a/scripts/depmod.sh +++ b/scripts/depmod.sh @@ -10,10 +10,16 @@ DEPMOD=$1 KERNELRELEASE=$2 SYMBOL_PREFIX=$3 -if ! test -r System.map -a -x "$DEPMOD"; then +if ! test -r System.map ; then exit 0 fi +if [ -z $(command -v $DEPMOD) ]; then + echo "'make modules_install' requires $DEPMOD. Please install it." >&2 + echo "This is probably in the kmod package." >&2 + exit 1 +fi + # older versions of depmod don't support -P # support was added in module-init-tools 3.13 if test -n "$SYMBOL_PREFIX"; then From b39ac2f453c56158c0945c0dc8685518760bd457 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 18 Jun 2018 10:22:37 -0700 Subject: [PATCH 236/392] crypto: vmac - require a block cipher with 128-bit block size commit 73bf20ef3df262026c3470241ae4ac8196943ffa upstream. The VMAC template assumes the block cipher has a 128-bit block size, but it failed to check for that. Thus it was possible to instantiate it using a 64-bit block size cipher, e.g. "vmac(cast5)", causing uninitialized memory to be used. Add the needed check when instantiating the template. Fixes: f1939f7c5645 ("crypto: vmac - New hash algorithm for intel_txt support") Cc: # v2.6.32+ Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/vmac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crypto/vmac.c b/crypto/vmac.c index df76a816cfb2..3034454a3713 100644 --- a/crypto/vmac.c +++ b/crypto/vmac.c @@ -655,6 +655,10 @@ static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) if (IS_ERR(alg)) return PTR_ERR(alg); + err = -EINVAL; + if (alg->cra_blocksize != 16) + goto out_put_alg; + inst = shash_alloc_instance("vmac", alg); err = PTR_ERR(inst); if (IS_ERR(inst)) From 58a60fc8e062fd61859c5aa7a0756d20517961b3 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 18 Jun 2018 10:22:38 -0700 Subject: [PATCH 237/392] crypto: vmac - separate tfm and request context commit bb29648102335586e9a66289a1d98a0cb392b6e5 upstream. syzbot reported a crash in vmac_final() when multiple threads concurrently use the same "vmac(aes)" transform through AF_ALG. The bug is pretty fundamental: the VMAC template doesn't separate per-request state from per-tfm (per-key) state like the other hash algorithms do, but rather stores it all in the tfm context. That's wrong. Also, vmac_final() incorrectly zeroes most of the state including the derived keys and cached pseudorandom pad. Therefore, only the first VMAC invocation with a given key calculates the correct digest. Fix these bugs by splitting the per-tfm state from the per-request state and using the proper init/update/final sequencing for requests. Reproducer for the crash: #include #include #include int main() { int fd; struct sockaddr_alg addr = { .salg_type = "hash", .salg_name = "vmac(aes)", }; char buf[256] = { 0 }; fd = socket(AF_ALG, SOCK_SEQPACKET, 0); bind(fd, (void *)&addr, sizeof(addr)); setsockopt(fd, SOL_ALG, ALG_SET_KEY, buf, 16); fork(); fd = accept(fd, NULL, NULL); for (;;) write(fd, buf, 256); } The immediate cause of the crash is that vmac_ctx_t.partial_size exceeds VMAC_NHBYTES, causing vmac_final() to memset() a negative length. Reported-by: syzbot+264bca3a6e8d645550d3@syzkaller.appspotmail.com Fixes: f1939f7c5645 ("crypto: vmac - New hash algorithm for intel_txt support") Cc: # v2.6.32+ Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/vmac.c | 408 +++++++++++++++++++----------------------- include/crypto/vmac.h | 63 ------- 2 files changed, 181 insertions(+), 290 deletions(-) delete mode 100644 include/crypto/vmac.h diff --git a/crypto/vmac.c b/crypto/vmac.c index 3034454a3713..bb2fc787d615 100644 --- a/crypto/vmac.c +++ b/crypto/vmac.c @@ -1,6 +1,10 @@ /* - * Modified to interface to the Linux kernel + * VMAC: Message Authentication Code using Universal Hashing + * + * Reference: https://tools.ietf.org/html/draft-krovetz-vmac-01 + * * Copyright (c) 2009, Intel Corporation. + * Copyright (c) 2018, Google Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,14 +20,15 @@ * Place - Suite 330, Boston, MA 02111-1307 USA. */ -/* -------------------------------------------------------------------------- - * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. - * This implementation is herby placed in the public domain. - * The authors offers no warranty. Use at your own risk. - * Please send bug reports to the authors. - * Last modified: 17 APR 08, 1700 PDT - * ----------------------------------------------------------------------- */ +/* + * Derived from: + * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. + * This implementation is herby placed in the public domain. + * The authors offers no warranty. Use at your own risk. + * Last modified: 17 APR 08, 1700 PDT + */ +#include #include #include #include @@ -31,9 +36,35 @@ #include #include #include -#include #include +/* + * User definable settings. + */ +#define VMAC_TAG_LEN 64 +#define VMAC_KEY_SIZE 128/* Must be 128, 192 or 256 */ +#define VMAC_KEY_LEN (VMAC_KEY_SIZE/8) +#define VMAC_NHBYTES 128/* Must 2^i for any 3 < i < 13 Standard = 128*/ + +/* per-transform (per-key) context */ +struct vmac_tfm_ctx { + struct crypto_cipher *cipher; + u64 nhkey[(VMAC_NHBYTES/8)+2*(VMAC_TAG_LEN/64-1)]; + u64 polykey[2*VMAC_TAG_LEN/64]; + u64 l3key[2*VMAC_TAG_LEN/64]; +}; + +/* per-request context */ +struct vmac_desc_ctx { + union { + u8 partial[VMAC_NHBYTES]; /* partial block */ + __le64 partial_words[VMAC_NHBYTES / 8]; + }; + unsigned int partial_size; /* size of the partial block */ + bool first_block_processed; + u64 polytmp[2*VMAC_TAG_LEN/64]; /* running total of L2-hash */ +}; + /* * Constants and masks */ @@ -318,13 +349,6 @@ static void poly_step_func(u64 *ahi, u64 *alo, } while (0) #endif -static void vhash_abort(struct vmac_ctx *ctx) -{ - ctx->polytmp[0] = ctx->polykey[0] ; - ctx->polytmp[1] = ctx->polykey[1] ; - ctx->first_block_processed = 0; -} - static u64 l3hash(u64 p1, u64 p2, u64 k1, u64 k2, u64 len) { u64 rh, rl, t, z = 0; @@ -364,280 +388,209 @@ static u64 l3hash(u64 p1, u64 p2, u64 k1, u64 k2, u64 len) return rl; } -static void vhash_update(const unsigned char *m, - unsigned int mbytes, /* Pos multiple of VMAC_NHBYTES */ - struct vmac_ctx *ctx) +/* L1 and L2-hash one or more VMAC_NHBYTES-byte blocks */ +static void vhash_blocks(const struct vmac_tfm_ctx *tctx, + struct vmac_desc_ctx *dctx, + const __le64 *mptr, unsigned int blocks) { - u64 rh, rl, *mptr; - const u64 *kptr = (u64 *)ctx->nhkey; - int i; - u64 ch, cl; - u64 pkh = ctx->polykey[0]; - u64 pkl = ctx->polykey[1]; - - if (!mbytes) - return; - - BUG_ON(mbytes % VMAC_NHBYTES); - - mptr = (u64 *)m; - i = mbytes / VMAC_NHBYTES; /* Must be non-zero */ - - ch = ctx->polytmp[0]; - cl = ctx->polytmp[1]; - - if (!ctx->first_block_processed) { - ctx->first_block_processed = 1; + const u64 *kptr = tctx->nhkey; + const u64 pkh = tctx->polykey[0]; + const u64 pkl = tctx->polykey[1]; + u64 ch = dctx->polytmp[0]; + u64 cl = dctx->polytmp[1]; + u64 rh, rl; + + if (!dctx->first_block_processed) { + dctx->first_block_processed = true; nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); rh &= m62; ADD128(ch, cl, rh, rl); mptr += (VMAC_NHBYTES/sizeof(u64)); - i--; + blocks--; } - while (i--) { + while (blocks--) { nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); rh &= m62; poly_step(ch, cl, pkh, pkl, rh, rl); mptr += (VMAC_NHBYTES/sizeof(u64)); } - ctx->polytmp[0] = ch; - ctx->polytmp[1] = cl; + dctx->polytmp[0] = ch; + dctx->polytmp[1] = cl; } -static u64 vhash(unsigned char m[], unsigned int mbytes, - u64 *tagl, struct vmac_ctx *ctx) +static int vmac_setkey(struct crypto_shash *tfm, + const u8 *key, unsigned int keylen) { - u64 rh, rl, *mptr; - const u64 *kptr = (u64 *)ctx->nhkey; - int i, remaining; - u64 ch, cl; - u64 pkh = ctx->polykey[0]; - u64 pkl = ctx->polykey[1]; - - mptr = (u64 *)m; - i = mbytes / VMAC_NHBYTES; - remaining = mbytes % VMAC_NHBYTES; - - if (ctx->first_block_processed) { - ch = ctx->polytmp[0]; - cl = ctx->polytmp[1]; - } else if (i) { - nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, ch, cl); - ch &= m62; - ADD128(ch, cl, pkh, pkl); - mptr += (VMAC_NHBYTES/sizeof(u64)); - i--; - } else if (remaining) { - nh_16(mptr, kptr, 2*((remaining+15)/16), ch, cl); - ch &= m62; - ADD128(ch, cl, pkh, pkl); - mptr += (VMAC_NHBYTES/sizeof(u64)); - goto do_l3; - } else {/* Empty String */ - ch = pkh; cl = pkl; - goto do_l3; - } - - while (i--) { - nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); - rh &= m62; - poly_step(ch, cl, pkh, pkl, rh, rl); - mptr += (VMAC_NHBYTES/sizeof(u64)); - } - if (remaining) { - nh_16(mptr, kptr, 2*((remaining+15)/16), rh, rl); - rh &= m62; - poly_step(ch, cl, pkh, pkl, rh, rl); - } - -do_l3: - vhash_abort(ctx); - remaining *= 8; - return l3hash(ch, cl, ctx->l3key[0], ctx->l3key[1], remaining); -} + struct vmac_tfm_ctx *tctx = crypto_shash_ctx(tfm); + __be64 out[2]; + u8 in[16] = { 0 }; + unsigned int i; + int err; -static u64 vmac(unsigned char m[], unsigned int mbytes, - const unsigned char n[16], u64 *tagl, - struct vmac_ctx_t *ctx) -{ - u64 *in_n, *out_p; - u64 p, h; - int i; - - in_n = ctx->__vmac_ctx.cached_nonce; - out_p = ctx->__vmac_ctx.cached_aes; - - i = n[15] & 1; - if ((*(u64 *)(n+8) != in_n[1]) || (*(u64 *)(n) != in_n[0])) { - in_n[0] = *(u64 *)(n); - in_n[1] = *(u64 *)(n+8); - ((unsigned char *)in_n)[15] &= 0xFE; - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out_p, (unsigned char *)in_n); - - ((unsigned char *)in_n)[15] |= (unsigned char)(1-i); + if (keylen != VMAC_KEY_LEN) { + crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; } - p = be64_to_cpup(out_p + i); - h = vhash(m, mbytes, (u64 *)0, &ctx->__vmac_ctx); - return le64_to_cpu(p + h); -} -static int vmac_set_key(unsigned char user_key[], struct vmac_ctx_t *ctx) -{ - u64 in[2] = {0}, out[2]; - unsigned i; - int err = 0; - - err = crypto_cipher_setkey(ctx->child, user_key, VMAC_KEY_LEN); + err = crypto_cipher_setkey(tctx->cipher, key, keylen); if (err) return err; /* Fill nh key */ - ((unsigned char *)in)[0] = 0x80; - for (i = 0; i < sizeof(ctx->__vmac_ctx.nhkey)/8; i += 2) { - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.nhkey[i] = be64_to_cpup(out); - ctx->__vmac_ctx.nhkey[i+1] = be64_to_cpup(out+1); - ((unsigned char *)in)[15] += 1; + in[0] = 0x80; + for (i = 0; i < ARRAY_SIZE(tctx->nhkey); i += 2) { + crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); + tctx->nhkey[i] = be64_to_cpu(out[0]); + tctx->nhkey[i+1] = be64_to_cpu(out[1]); + in[15]++; } /* Fill poly key */ - ((unsigned char *)in)[0] = 0xC0; - in[1] = 0; - for (i = 0; i < sizeof(ctx->__vmac_ctx.polykey)/8; i += 2) { - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.polytmp[i] = - ctx->__vmac_ctx.polykey[i] = - be64_to_cpup(out) & mpoly; - ctx->__vmac_ctx.polytmp[i+1] = - ctx->__vmac_ctx.polykey[i+1] = - be64_to_cpup(out+1) & mpoly; - ((unsigned char *)in)[15] += 1; + in[0] = 0xC0; + in[15] = 0; + for (i = 0; i < ARRAY_SIZE(tctx->polykey); i += 2) { + crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); + tctx->polykey[i] = be64_to_cpu(out[0]) & mpoly; + tctx->polykey[i+1] = be64_to_cpu(out[1]) & mpoly; + in[15]++; } /* Fill ip key */ - ((unsigned char *)in)[0] = 0xE0; - in[1] = 0; - for (i = 0; i < sizeof(ctx->__vmac_ctx.l3key)/8; i += 2) { + in[0] = 0xE0; + in[15] = 0; + for (i = 0; i < ARRAY_SIZE(tctx->l3key); i += 2) { do { - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.l3key[i] = be64_to_cpup(out); - ctx->__vmac_ctx.l3key[i+1] = be64_to_cpup(out+1); - ((unsigned char *)in)[15] += 1; - } while (ctx->__vmac_ctx.l3key[i] >= p64 - || ctx->__vmac_ctx.l3key[i+1] >= p64); + crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); + tctx->l3key[i] = be64_to_cpu(out[0]); + tctx->l3key[i+1] = be64_to_cpu(out[1]); + in[15]++; + } while (tctx->l3key[i] >= p64 || tctx->l3key[i+1] >= p64); } - /* Invalidate nonce/aes cache and reset other elements */ - ctx->__vmac_ctx.cached_nonce[0] = (u64)-1; /* Ensure illegal nonce */ - ctx->__vmac_ctx.cached_nonce[1] = (u64)0; /* Ensure illegal nonce */ - ctx->__vmac_ctx.first_block_processed = 0; - - return err; + return 0; } -static int vmac_setkey(struct crypto_shash *parent, - const u8 *key, unsigned int keylen) +static int vmac_init(struct shash_desc *desc) { - struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); - - if (keylen != VMAC_KEY_LEN) { - crypto_shash_set_flags(parent, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - return vmac_set_key((u8 *)key, ctx); -} + const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); -static int vmac_init(struct shash_desc *pdesc) -{ + dctx->partial_size = 0; + dctx->first_block_processed = false; + memcpy(dctx->polytmp, tctx->polykey, sizeof(dctx->polytmp)); return 0; } -static int vmac_update(struct shash_desc *pdesc, const u8 *p, - unsigned int len) +static int vmac_update(struct shash_desc *desc, const u8 *p, unsigned int len) { - struct crypto_shash *parent = pdesc->tfm; - struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); - int expand; - int min; - - expand = VMAC_NHBYTES - ctx->partial_size > 0 ? - VMAC_NHBYTES - ctx->partial_size : 0; - - min = len < expand ? len : expand; - - memcpy(ctx->partial + ctx->partial_size, p, min); - ctx->partial_size += min; - - if (len < expand) - return 0; - - vhash_update(ctx->partial, VMAC_NHBYTES, &ctx->__vmac_ctx); - ctx->partial_size = 0; - - len -= expand; - p += expand; + const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); + unsigned int n; + + if (dctx->partial_size) { + n = min(len, VMAC_NHBYTES - dctx->partial_size); + memcpy(&dctx->partial[dctx->partial_size], p, n); + dctx->partial_size += n; + p += n; + len -= n; + if (dctx->partial_size == VMAC_NHBYTES) { + vhash_blocks(tctx, dctx, dctx->partial_words, 1); + dctx->partial_size = 0; + } + } - if (len % VMAC_NHBYTES) { - memcpy(ctx->partial, p + len - (len % VMAC_NHBYTES), - len % VMAC_NHBYTES); - ctx->partial_size = len % VMAC_NHBYTES; + if (len >= VMAC_NHBYTES) { + n = round_down(len, VMAC_NHBYTES); + /* TODO: 'p' may be misaligned here */ + vhash_blocks(tctx, dctx, (const __le64 *)p, n / VMAC_NHBYTES); + p += n; + len -= n; } - vhash_update(p, len - len % VMAC_NHBYTES, &ctx->__vmac_ctx); + if (len) { + memcpy(dctx->partial, p, len); + dctx->partial_size = len; + } return 0; } -static int vmac_final(struct shash_desc *pdesc, u8 *out) +static u64 vhash_final(const struct vmac_tfm_ctx *tctx, + struct vmac_desc_ctx *dctx) { - struct crypto_shash *parent = pdesc->tfm; - struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); - vmac_t mac; - u8 nonce[16] = {}; - - /* vmac() ends up accessing outside the array bounds that - * we specify. In appears to access up to the next 2-word - * boundary. We'll just be uber cautious and zero the - * unwritten bytes in the buffer. - */ - if (ctx->partial_size) { - memset(ctx->partial + ctx->partial_size, 0, - VMAC_NHBYTES - ctx->partial_size); + unsigned int partial = dctx->partial_size; + u64 ch = dctx->polytmp[0]; + u64 cl = dctx->polytmp[1]; + + /* L1 and L2-hash the final block if needed */ + if (partial) { + /* Zero-pad to next 128-bit boundary */ + unsigned int n = round_up(partial, 16); + u64 rh, rl; + + memset(&dctx->partial[partial], 0, n - partial); + nh_16(dctx->partial_words, tctx->nhkey, n / 8, rh, rl); + rh &= m62; + if (dctx->first_block_processed) + poly_step(ch, cl, tctx->polykey[0], tctx->polykey[1], + rh, rl); + else + ADD128(ch, cl, rh, rl); } - mac = vmac(ctx->partial, ctx->partial_size, nonce, NULL, ctx); - memcpy(out, &mac, sizeof(vmac_t)); - memzero_explicit(&mac, sizeof(vmac_t)); - memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx)); - ctx->partial_size = 0; + + /* L3-hash the 128-bit output of L2-hash */ + return l3hash(ch, cl, tctx->l3key[0], tctx->l3key[1], partial * 8); +} + +static int vmac_final(struct shash_desc *desc, u8 *out) +{ + const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); + static const u8 nonce[16] = {}; /* TODO: this is insecure */ + union { + u8 bytes[16]; + __be64 pads[2]; + } block; + int index; + u64 hash, pad; + + /* Finish calculating the VHASH of the message */ + hash = vhash_final(tctx, dctx); + + /* Generate pseudorandom pad by encrypting the nonce */ + memcpy(&block, nonce, 16); + index = block.bytes[15] & 1; + block.bytes[15] &= ~1; + crypto_cipher_encrypt_one(tctx->cipher, block.bytes, block.bytes); + pad = be64_to_cpu(block.pads[index]); + + /* The VMAC is the sum of VHASH and the pseudorandom pad */ + put_unaligned_le64(hash + pad, out); return 0; } static int vmac_init_tfm(struct crypto_tfm *tfm) { - struct crypto_cipher *cipher; - struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); struct crypto_spawn *spawn = crypto_instance_ctx(inst); - struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm); + struct vmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; cipher = crypto_spawn_cipher(spawn); if (IS_ERR(cipher)) return PTR_ERR(cipher); - ctx->child = cipher; + tctx->cipher = cipher; return 0; } static void vmac_exit_tfm(struct crypto_tfm *tfm) { - struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm); - crypto_free_cipher(ctx->child); + struct vmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm); + + crypto_free_cipher(tctx->cipher); } static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) @@ -674,11 +627,12 @@ static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.base.cra_blocksize = alg->cra_blocksize; inst->alg.base.cra_alignmask = alg->cra_alignmask; - inst->alg.digestsize = sizeof(vmac_t); - inst->alg.base.cra_ctxsize = sizeof(struct vmac_ctx_t); + inst->alg.base.cra_ctxsize = sizeof(struct vmac_tfm_ctx); inst->alg.base.cra_init = vmac_init_tfm; inst->alg.base.cra_exit = vmac_exit_tfm; + inst->alg.descsize = sizeof(struct vmac_desc_ctx); + inst->alg.digestsize = VMAC_TAG_LEN / 8; inst->alg.init = vmac_init; inst->alg.update = vmac_update; inst->alg.final = vmac_final; diff --git a/include/crypto/vmac.h b/include/crypto/vmac.h deleted file mode 100644 index 6b700c7b2fe1..000000000000 --- a/include/crypto/vmac.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Modified to interface to the Linux kernel - * Copyright (c) 2009, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - */ - -#ifndef __CRYPTO_VMAC_H -#define __CRYPTO_VMAC_H - -/* -------------------------------------------------------------------------- - * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. - * This implementation is herby placed in the public domain. - * The authors offers no warranty. Use at your own risk. - * Please send bug reports to the authors. - * Last modified: 17 APR 08, 1700 PDT - * ----------------------------------------------------------------------- */ - -/* - * User definable settings. - */ -#define VMAC_TAG_LEN 64 -#define VMAC_KEY_SIZE 128/* Must be 128, 192 or 256 */ -#define VMAC_KEY_LEN (VMAC_KEY_SIZE/8) -#define VMAC_NHBYTES 128/* Must 2^i for any 3 < i < 13 Standard = 128*/ - -/* - * This implementation uses u32 and u64 as names for unsigned 32- - * and 64-bit integer types. These are defined in C99 stdint.h. The - * following may need adaptation if you are not running a C99 or - * Microsoft C environment. - */ -struct vmac_ctx { - u64 nhkey[(VMAC_NHBYTES/8)+2*(VMAC_TAG_LEN/64-1)]; - u64 polykey[2*VMAC_TAG_LEN/64]; - u64 l3key[2*VMAC_TAG_LEN/64]; - u64 polytmp[2*VMAC_TAG_LEN/64]; - u64 cached_nonce[2]; - u64 cached_aes[2]; - int first_block_processed; -}; - -typedef u64 vmac_t; - -struct vmac_ctx_t { - struct crypto_cipher *child; - struct vmac_ctx __vmac_ctx; - u8 partial[VMAC_NHBYTES]; /* partial block */ - int partial_size; /* size of the partial block */ -}; - -#endif /* __CRYPTO_VMAC_H */ From c34837deef0c7294e6a846c778df08ebbcefe0de Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 23 Jul 2018 10:54:57 -0700 Subject: [PATCH 238/392] crypto: blkcipher - fix crash flushing dcache in error path commit 0868def3e4100591e7a1fdbf3eed1439cc8f7ca3 upstream. Like the skcipher_walk case: scatterwalk_done() is only meant to be called after a nonzero number of bytes have been processed, since scatterwalk_pagedone() will flush the dcache of the *previous* page. But in the error case of blkcipher_walk_done(), e.g. if the input wasn't an integer number of blocks, scatterwalk_done() was actually called after advancing 0 bytes. This caused a crash ("BUG: unable to handle kernel paging request") during '!PageSlab(page)' on architectures like arm and arm64 that define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE, provided that the input was page-aligned as in that case walk->offset == 0. Fix it by reorganizing blkcipher_walk_done() to skip the scatterwalk_advance() and scatterwalk_done() if an error has occurred. This bug was found by syzkaller fuzzing. Reproducer, assuming ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE: #include #include #include int main() { struct sockaddr_alg addr = { .salg_type = "skcipher", .salg_name = "ecb(aes-generic)", }; char buffer[4096] __attribute__((aligned(4096))) = { 0 }; int fd; fd = socket(AF_ALG, SOCK_SEQPACKET, 0); bind(fd, (void *)&addr, sizeof(addr)); setsockopt(fd, SOL_ALG, ALG_SET_KEY, buffer, 16); fd = accept(fd, NULL, NULL); write(fd, buffer, 15); read(fd, buffer, 15); } Reported-by: Liu Chao Fixes: 5cde0af2a982 ("[CRYPTO] cipher: Added block cipher type") Cc: # v2.6.19+ Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/blkcipher.c | 54 ++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index f25799f351f7..5ebfdd0d4543 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -70,19 +70,18 @@ static inline u8 *blkcipher_get_spot(u8 *start, unsigned int len) return max(start, end_page); } -static inline unsigned int blkcipher_done_slow(struct blkcipher_walk *walk, - unsigned int bsize) +static inline void blkcipher_done_slow(struct blkcipher_walk *walk, + unsigned int bsize) { u8 *addr; addr = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1); addr = blkcipher_get_spot(addr, bsize); scatterwalk_copychunks(addr, &walk->out, bsize, 1); - return bsize; } -static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk, - unsigned int n) +static inline void blkcipher_done_fast(struct blkcipher_walk *walk, + unsigned int n) { if (walk->flags & BLKCIPHER_WALK_COPY) { blkcipher_map_dst(walk); @@ -96,49 +95,48 @@ static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk, scatterwalk_advance(&walk->in, n); scatterwalk_advance(&walk->out, n); - - return n; } int blkcipher_walk_done(struct blkcipher_desc *desc, struct blkcipher_walk *walk, int err) { - unsigned int nbytes = 0; + unsigned int n; /* bytes processed */ + bool more; - if (likely(err >= 0)) { - unsigned int n = walk->nbytes - err; + if (unlikely(err < 0)) + goto finish; - if (likely(!(walk->flags & BLKCIPHER_WALK_SLOW))) - n = blkcipher_done_fast(walk, n); - else if (WARN_ON(err)) { - err = -EINVAL; - goto err; - } else - n = blkcipher_done_slow(walk, n); + n = walk->nbytes - err; + walk->total -= n; + more = (walk->total != 0); - nbytes = walk->total - n; - err = 0; + if (likely(!(walk->flags & BLKCIPHER_WALK_SLOW))) { + blkcipher_done_fast(walk, n); + } else { + if (WARN_ON(err)) { + /* unexpected case; didn't process all bytes */ + err = -EINVAL; + goto finish; + } + blkcipher_done_slow(walk, n); } - scatterwalk_done(&walk->in, 0, nbytes); - scatterwalk_done(&walk->out, 1, nbytes); - -err: - walk->total = nbytes; - walk->nbytes = nbytes; + scatterwalk_done(&walk->in, 0, more); + scatterwalk_done(&walk->out, 1, more); - if (nbytes) { + if (more) { crypto_yield(desc->flags); return blkcipher_walk_next(desc, walk); } - + err = 0; +finish: + walk->nbytes = 0; if (walk->iv != desc->info) memcpy(desc->info, walk->iv, walk->ivsize); if (walk->buffer != walk->page) kfree(walk->buffer); if (walk->page) free_page((unsigned long)walk->page); - return err; } EXPORT_SYMBOL_GPL(blkcipher_walk_done); From 4b55d18a7b09dae3af7d9b5b69e55b9a0edd5cd7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 23 Jul 2018 10:54:58 -0700 Subject: [PATCH 239/392] crypto: ablkcipher - fix crash flushing dcache in error path commit 318abdfbe708aaaa652c79fb500e9bd60521f9dc upstream. Like the skcipher_walk and blkcipher_walk cases: scatterwalk_done() is only meant to be called after a nonzero number of bytes have been processed, since scatterwalk_pagedone() will flush the dcache of the *previous* page. But in the error case of ablkcipher_walk_done(), e.g. if the input wasn't an integer number of blocks, scatterwalk_done() was actually called after advancing 0 bytes. This caused a crash ("BUG: unable to handle kernel paging request") during '!PageSlab(page)' on architectures like arm and arm64 that define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE, provided that the input was page-aligned as in that case walk->offset == 0. Fix it by reorganizing ablkcipher_walk_done() to skip the scatterwalk_advance() and scatterwalk_done() if an error has occurred. Reported-by: Liu Chao Fixes: bf06099db18a ("crypto: skcipher - Add ablkcipher_walk interfaces") Cc: # v2.6.35+ Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/ablkcipher.c | 57 +++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 520729d898fe..5061d7ad33e4 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -72,11 +72,9 @@ static inline u8 *ablkcipher_get_spot(u8 *start, unsigned int len) return max(start, end_page); } -static inline unsigned int ablkcipher_done_slow(struct ablkcipher_walk *walk, - unsigned int bsize) +static inline void ablkcipher_done_slow(struct ablkcipher_walk *walk, + unsigned int n) { - unsigned int n = bsize; - for (;;) { unsigned int len_this_page = scatterwalk_pagelen(&walk->out); @@ -88,17 +86,13 @@ static inline unsigned int ablkcipher_done_slow(struct ablkcipher_walk *walk, n -= len_this_page; scatterwalk_start(&walk->out, scatterwalk_sg_next(walk->out.sg)); } - - return bsize; } -static inline unsigned int ablkcipher_done_fast(struct ablkcipher_walk *walk, - unsigned int n) +static inline void ablkcipher_done_fast(struct ablkcipher_walk *walk, + unsigned int n) { scatterwalk_advance(&walk->in, n); scatterwalk_advance(&walk->out, n); - - return n; } static int ablkcipher_walk_next(struct ablkcipher_request *req, @@ -108,39 +102,40 @@ int ablkcipher_walk_done(struct ablkcipher_request *req, struct ablkcipher_walk *walk, int err) { struct crypto_tfm *tfm = req->base.tfm; - unsigned int nbytes = 0; + unsigned int n; /* bytes processed */ + bool more; - if (likely(err >= 0)) { - unsigned int n = walk->nbytes - err; + if (unlikely(err < 0)) + goto finish; - if (likely(!(walk->flags & ABLKCIPHER_WALK_SLOW))) - n = ablkcipher_done_fast(walk, n); - else if (WARN_ON(err)) { - err = -EINVAL; - goto err; - } else - n = ablkcipher_done_slow(walk, n); + n = walk->nbytes - err; + walk->total -= n; + more = (walk->total != 0); - nbytes = walk->total - n; - err = 0; + if (likely(!(walk->flags & ABLKCIPHER_WALK_SLOW))) { + ablkcipher_done_fast(walk, n); + } else { + if (WARN_ON(err)) { + /* unexpected case; didn't process all bytes */ + err = -EINVAL; + goto finish; + } + ablkcipher_done_slow(walk, n); } - scatterwalk_done(&walk->in, 0, nbytes); - scatterwalk_done(&walk->out, 1, nbytes); - -err: - walk->total = nbytes; - walk->nbytes = nbytes; + scatterwalk_done(&walk->in, 0, more); + scatterwalk_done(&walk->out, 1, more); - if (nbytes) { + if (more) { crypto_yield(req->base.flags); return ablkcipher_walk_next(req, walk); } - + err = 0; +finish: + walk->nbytes = 0; if (walk->iv != req->info) memcpy(req->info, walk->iv, tfm->crt_ablkcipher.ivsize); kfree(walk->iv_buffer); - return err; } EXPORT_SYMBOL_GPL(ablkcipher_walk_done); From adfdcfe1c7cd5f163855b0d3ea5d3a75efddd576 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Tue, 31 Jul 2018 15:02:13 -0700 Subject: [PATCH 240/392] Bluetooth: hidp: buffer overflow in hidp_process_report commit 7992c18810e568b95c869b227137a2215702a805 upstream. CVE-2018-9363 The buffer length is unsigned at all layers, but gets cast to int and checked in hidp_process_report and can lead to a buffer overflow. Switch len parameter to unsigned int to resolve issue. This affects 3.18 and newer kernels. Signed-off-by: Mark Salyzyn Fixes: a4b1b5877b514b276f0f31efe02388a9c2836728 ("HID: Bluetooth: hidp: make sure input buffers are big enough") Cc: Marcel Holtmann Cc: Johan Hedberg Cc: "David S. Miller" Cc: Kees Cook Cc: Benjamin Tissoires Cc: linux-bluetooth@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: security@kernel.org Cc: kernel-team@android.com Acked-by: Kees Cook Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hidp/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 9f5273a0be7a..4f41b245ce5b 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -416,8 +416,8 @@ static void hidp_del_timer(struct hidp_session *session) del_timer(&session->timer); } -static void hidp_process_report(struct hidp_session *session, - int type, const u8 *data, int len, int intr) +static void hidp_process_report(struct hidp_session *session, int type, + const u8 *data, unsigned int len, int intr) { if (len > HID_MAX_BUFFER_SIZE) len = HID_MAX_BUFFER_SIZE; From 18e6ee0440a7ab853e4ca0f1403eeef1803ed970 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Aug 2018 20:54:56 +0200 Subject: [PATCH 241/392] Linux 3.18.119 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5c3464b5bb1e..6f85cc732008 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 18 -SUBLEVEL = 118 +SUBLEVEL = 119 EXTRAVERSION = NAME = Diseased Newt From bbe8a2d4992f611c610f843a63410c5950a2dae5 Mon Sep 17 00:00:00 2001 From: Li Jinyue Date: Thu, 14 Dec 2017 17:04:54 +0800 Subject: [PATCH 242/392] BACKPORT: futex: Prevent overflow by strengthen input validation UBSAN reports signed integer overflow in kernel/futex.c: UBSAN: Undefined behaviour in kernel/futex.c:2041:18 signed integer overflow: 0 - -2147483648 cannot be represented in type 'int' Add a sanity check to catch negative values of nr_wake and nr_requeue. Signed-off-by: Li Jinyue Signed-off-by: Thomas Gleixner Signed-off-by: Erick Reyes Signed-off-by: Oleg Matcovschi Cc: peterz@infradead.org Cc: dvhart@infradead.org Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/1513242294-31786-1-git-send-email-lijinyue@huawei.com Cherry-picked from fbe0e839d1e22d88810f3ee3e2f1479be4c0aa4a Bug: 76106267 Change-Id: I954cc2848678318b60ec3f103d0c15f87b4605a4 Git-repo: https://android.googlesource.com/kernel/msm Git-commit: cf94cf625ff65a10864321006482e547f023926d Signed-off-by: Dennis Cagle --- kernel/futex.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/futex.c b/kernel/futex.c index bd00696741ed..a8c6a9dbedab 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1514,6 +1514,9 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, struct futex_hash_bucket *hb1, *hb2; struct futex_q *this, *next; + if (nr_wake < 0 || nr_requeue < 0) + return -EINVAL; + if (requeue_pi) { /* * Requeue PI only works on two distinct uaddrs. This From 73a07e5e1afb7edb36a3d4ae8926f84825559c95 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 10 May 2017 09:53:40 +0200 Subject: [PATCH 243/392] UPSTREAM: scsi: sg: don't return bogus Sg_requests If the list search in sg_get_rq_mark() fails to find a valid request, we return a bogus element. This then can later lead to a GPF in sg_remove_scat(). So don't return bogus Sg_requests in sg_get_rq_mark() but NULL in case the list search doesn't find a valid request. Bug: 79090045 Signed-off-by: Johannes Thumshirn Reported-by: Andrey Konovalov Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: Doug Gilbert Reviewed-by: Hannes Reinecke Acked-by: Doug Gilbert Signed-off-by: Martin K. Petersen Signed-off-by: Chenbo Feng Git-repo: https://android.googlesource.com/kernel/msm Git-commit: 58408c68e4d7abc1957ca8cc3fec69619578b06a Change-Id: If95d1a8eef3748c9937201e524184b89a5eaaf2e Bug: 75300370 Signed-off-by: Srinivasa Rao Kuppala --- drivers/scsi/sg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 73c116ba4aba..c1abb35c896a 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2124,11 +2124,12 @@ sg_get_rq_mark(Sg_fd * sfp, int pack_id) if ((1 == resp->done) && (!resp->sg_io_owned) && ((-1 == pack_id) || (resp->header.pack_id == pack_id))) { resp->done = 2; /* guard against other readers */ - break; + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return resp; } } write_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return resp; + return NULL; } /* always adds to end of list */ From 6bf1f9eebe5bb09ade3fc40d29267492b3967f2a Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Thu, 8 Mar 2018 11:50:49 +0530 Subject: [PATCH 244/392] diag: Allocate DCI memory using vzalloc instead of kzalloc Currently there is a possibility of kmalloc failing when system is running low on memory condition. The patch changes the dci memory allocation from kzalloc to vzalloc. CRs-Fixed: 2195818 Change-Id: I92b20d8e77ce5b2a96212f9d0757fbbff2703891 Signed-off-by: Hardik Arya --- drivers/char/diag/diag_dci.c | 41 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index e195d9d0931c..6e24f475d65d 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef CONFIG_DIAG_OVER_USB #include #endif @@ -229,7 +230,7 @@ static int diag_dci_init_buffer(struct diag_dci_buffer_t *buffer, int type) switch (type) { case DCI_BUF_PRIMARY: buffer->capacity = IN_BUF_SIZE; - buffer->data = kzalloc(buffer->capacity, GFP_KERNEL); + buffer->data = vzalloc(buffer->capacity); if (!buffer->data) return -ENOMEM; break; @@ -239,7 +240,7 @@ static int diag_dci_init_buffer(struct diag_dci_buffer_t *buffer, int type) break; case DCI_BUF_CMD: buffer->capacity = DIAG_MAX_REQ_SIZE + DCI_BUF_SIZE; - buffer->data = kzalloc(buffer->capacity, GFP_KERNEL); + buffer->data = vzalloc(buffer->capacity); if (!buffer->data) return -ENOMEM; break; @@ -2615,7 +2616,7 @@ static int diag_dci_init_remote(void) create_dci_event_mask_tbl(temp->event_mask_composite); } - partial_pkt.data = kzalloc(MAX_DCI_PACKET_SZ, GFP_KERNEL); + partial_pkt.data = vzalloc(MAX_DCI_PACKET_SZ); if (!partial_pkt.data) { pr_err("diag: Unable to create partial pkt data\n"); return -ENOMEM; @@ -2671,7 +2672,7 @@ int diag_dci_init(void) goto err; if (driver->apps_dci_buf == NULL) { - driver->apps_dci_buf = kzalloc(DCI_BUF_SIZE, GFP_KERNEL); + driver->apps_dci_buf = vzalloc(DCI_BUF_SIZE); if (driver->apps_dci_buf == NULL) goto err; } @@ -2688,12 +2689,12 @@ int diag_dci_init(void) return DIAG_DCI_NO_ERROR; err: pr_err("diag: Could not initialize diag DCI buffers"); - kfree(driver->apps_dci_buf); + vfree(driver->apps_dci_buf); driver->apps_dci_buf = NULL; if (driver->diag_dci_wq) destroy_workqueue(driver->diag_dci_wq); - kfree(partial_pkt.data); + vfree(partial_pkt.data); partial_pkt.data = NULL; mutex_destroy(&driver->dci_mutex); mutex_destroy(&dci_log_mask_mutex); @@ -2713,9 +2714,9 @@ void diag_dci_channel_init(void) void diag_dci_exit(void) { - kfree(partial_pkt.data); + vfree(partial_pkt.data); partial_pkt.data = NULL; - kfree(driver->apps_dci_buf); + vfree(driver->apps_dci_buf); driver->apps_dci_buf = NULL; mutex_destroy(&driver->dci_mutex); mutex_destroy(&dci_log_mask_mutex); @@ -2855,7 +2856,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) new_entry->in_service = 0; INIT_LIST_HEAD(&new_entry->list_write_buf); mutex_init(&new_entry->write_buf_mutex); - new_entry->dci_log_mask = kzalloc(DCI_LOG_MASK_SIZE, GFP_KERNEL); + new_entry->dci_log_mask = vzalloc(DCI_LOG_MASK_SIZE); if (!new_entry->dci_log_mask) { pr_err("diag: Unable to create log mask for client, %d", driver->dci_client_id); @@ -2863,7 +2864,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) } create_dci_log_mask_tbl(new_entry->dci_log_mask, DCI_LOG_MASK_CLEAN); - new_entry->dci_event_mask = kzalloc(DCI_EVENT_MASK_SIZE, GFP_KERNEL); + new_entry->dci_event_mask = vzalloc(DCI_EVENT_MASK_SIZE); if (!new_entry->dci_event_mask) { pr_err("diag: Unable to create event mask for client, %d", driver->dci_client_id); @@ -2873,7 +2874,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) new_entry->buffers = kzalloc(new_entry->num_buffers * sizeof(struct diag_dci_buf_peripheral_t), - GFP_KERNEL); + GFP_KERNEL); if (!new_entry->buffers) { pr_err("diag: Unable to allocate buffers for peripherals in %s\n", __func__); @@ -2897,7 +2898,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) if (!proc_buf->buf_primary) goto fail_alloc; proc_buf->buf_cmd = kzalloc(sizeof(struct diag_dci_buffer_t), - GFP_KERNEL); + GFP_KERNEL); if (!proc_buf->buf_cmd) goto fail_alloc; err = diag_dci_init_buffer(proc_buf->buf_primary, @@ -2930,7 +2931,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) if (proc_buf) { mutex_destroy(&proc_buf->health_mutex); if (proc_buf->buf_primary) { - kfree(proc_buf->buf_primary->data); + vfree(proc_buf->buf_primary->data); proc_buf->buf_primary->data = NULL; mutex_destroy( &proc_buf->buf_primary->data_mutex); @@ -2938,7 +2939,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) kfree(proc_buf->buf_primary); proc_buf->buf_primary = NULL; if (proc_buf->buf_cmd) { - kfree(proc_buf->buf_cmd->data); + vfree(proc_buf->buf_cmd->data); proc_buf->buf_cmd->data = NULL; mutex_destroy( &proc_buf->buf_cmd->data_mutex); @@ -2947,9 +2948,9 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) proc_buf->buf_cmd = NULL; } } - kfree(new_entry->dci_event_mask); + vfree(new_entry->dci_event_mask); new_entry->dci_event_mask = NULL; - kfree(new_entry->dci_log_mask); + vfree(new_entry->dci_log_mask); new_entry->dci_log_mask = NULL; kfree(new_entry->buffers); new_entry->buffers = NULL; @@ -2984,7 +2985,7 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) * Clear the client's log and event masks, update the cumulative * masks and send the masks to peripherals */ - kfree(entry->dci_log_mask); + vfree(entry->dci_log_mask); entry->dci_log_mask = NULL; diag_dci_invalidate_cumulative_log_mask(token); if (token == DCI_LOCAL_PROC) @@ -2993,7 +2994,7 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) if (ret != DIAG_DCI_NO_ERROR) { return ret; } - kfree(entry->dci_event_mask); + vfree(entry->dci_event_mask); entry->dci_event_mask = NULL; diag_dci_invalidate_cumulative_event_mask(token); if (token == DCI_LOCAL_PROC) @@ -3057,12 +3058,12 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) } mutex_lock(&proc_buf->buf_primary->data_mutex); - kfree(proc_buf->buf_primary->data); + vfree(proc_buf->buf_primary->data); proc_buf->buf_primary->data = NULL; mutex_unlock(&proc_buf->buf_primary->data_mutex); mutex_lock(&proc_buf->buf_cmd->data_mutex); - kfree(proc_buf->buf_cmd->data); + vfree(proc_buf->buf_cmd->data); proc_buf->buf_cmd->data = NULL; mutex_unlock(&proc_buf->buf_cmd->data_mutex); From e439d82ede65e490f8715532e01c59851ae0b163 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Tue, 9 Feb 2016 11:15:14 -0800 Subject: [PATCH 245/392] futex: Remove requirement for lock_page() in get_futex_key() commit 65d8fc777f6dcfee12785c057a6b57f679641c90 upstream. When dealing with key handling for shared futexes, we can drastically reduce the usage/need of the page lock. 1) For anonymous pages, the associated futex object is the mm_struct which does not require the page lock. 2) For inode based, keys, we can check under RCU read lock if the page mapping is still valid and take reference to the inode. This just leaves one rare race that requires the page lock in the slow path when examining the swapcache. Additionally realtime users currently have a problem with the page lock being contended for unbounded periods of time during futex operations. Task A get_futex_key() lock_page() ---> preempted Now any other task trying to lock that page will have to wait until task A gets scheduled back in, which is an unbound time. With this patch, we pretty much have a lockless futex_get_key(). Experiments show that this patch can boost/speedup the hashing of shared futexes with the perf futex benchmarks (which is good for measuring such change) by up to 45% when there are high (> 100) thread counts on a 60 core Westmere. Lower counts are pretty much in the noise range or less than 10%, but mid range can be seen at over 30% overall throughput (hash ops/sec). This makes anon-mem shared futexes much closer to its private counterpart. Signed-off-by: Mel Gorman [ Ported on top of thp refcount rework, changelog, comments, fixes. ] Signed-off-by: Davidlohr Bueso Reviewed-by: Thomas Gleixner Cc: Chris Mason Cc: Darren Hart Cc: Hugh Dickins Cc: Linus Torvalds Cc: Mel Gorman Cc: Peter Zijlstra Cc: Sebastian Andrzej Siewior Cc: dave@stgolabs.net Link: http://lkml.kernel.org/r/1455045314-8305-3-git-send-email-dave@stgolabs.net Signed-off-by: Ingo Molnar Signed-off-by: Chenbo Feng Signed-off-by: Greg Kroah-Hartman Git-repo: https://android.googlesource.com/kernel/msm Git-commit: 93dcb09e29bb24a86aa7b7eff65e424f7dc98af2 Change-Id: I5c0f1e167973b387e78fb46b1d29fc2a1a9a0d0d Signed-off-by: Srinivasa Rao Kuppala --- kernel/futex.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 7 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index a8c6a9dbedab..e75c3c414af5 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -400,6 +400,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) unsigned long address = (unsigned long)uaddr; struct mm_struct *mm = current->mm; struct page *page, *page_head; + struct address_space *mapping; int err, ro = 0; /* @@ -478,7 +479,19 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) } #endif - lock_page(page_head); + /* + * The treatment of mapping from this point on is critical. The page + * lock protects many things but in this context the page lock + * stabilizes mapping, prevents inode freeing in the shared + * file-backed region case and guards against movement to swap cache. + * + * Strictly speaking the page lock is not needed in all cases being + * considered here and page lock forces unnecessarily serialization + * From this point on, mapping will be re-verified if necessary and + * page lock will be acquired only if it is unavoidable + */ + + mapping = READ_ONCE(page_head->mapping); /* * If page_head->mapping is NULL, then it cannot be a PageAnon @@ -495,18 +508,31 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) * shmem_writepage move it from filecache to swapcache beneath us: * an unlikely race, but we do need to retry for page_head->mapping. */ - if (!page_head->mapping) { - int shmem_swizzled = PageSwapCache(page_head); + if (unlikely(!mapping)) { + int shmem_swizzled; + + /* + * Page lock is required to identify which special case above + * applies. If this is really a shmem page then the page lock + * will prevent unexpected transitions. + */ + lock_page(page); + shmem_swizzled = PageSwapCache(page) || page->mapping; unlock_page(page_head); put_page(page_head); + if (shmem_swizzled) goto again; + return -EFAULT; } /* * Private mappings are handled in a simple way. * + * If the futex key is stored on an anonymous page, then the associated + * object is the mm which is implicitly pinned by the calling process. + * * NOTE: When userspace waits on a MAP_SHARED mapping, even if * it's a read-only handle, it's expected that futexes attach to * the object not the particular process. @@ -524,16 +550,74 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */ key->private.mm = mm; key->private.address = address; + + get_futex_key_refs(key); /* implies smp_mb(); (B) */ + } else { + struct inode *inode; + + /* + * The associated futex object in this case is the inode and + * the page->mapping must be traversed. Ordinarily this should + * be stabilised under page lock but it's not strictly + * necessary in this case as we just want to pin the inode, not + * update the radix tree or anything like that. + * + * The RCU read lock is taken as the inode is finally freed + * under RCU. If the mapping still matches expectations then the + * mapping->host can be safely accessed as being a valid inode. + */ + rcu_read_lock(); + + if (READ_ONCE(page_head->mapping) != mapping) { + rcu_read_unlock(); + put_page(page_head); + + goto again; + } + + inode = READ_ONCE(mapping->host); + if (!inode) { + rcu_read_unlock(); + put_page(page_head); + + goto again; + } + + /* + * Take a reference unless it is about to be freed. Previously + * this reference was taken by ihold under the page lock + * pinning the inode in place so i_lock was unnecessary. The + * only way for this check to fail is if the inode was + * truncated in parallel so warn for now if this happens. + * + * We are not calling into get_futex_key_refs() in file-backed + * cases, therefore a successful atomic_inc return below will + * guarantee that get_futex_key() will still imply smp_mb(); (B). + */ + if (WARN_ON_ONCE(!atomic_inc_not_zero(&inode->i_count))) { + rcu_read_unlock(); + put_page(page_head); + + goto again; + } + + /* Should be impossible but lets be paranoid for now */ + if (WARN_ON_ONCE(inode->i_mapping != mapping)) { + err = -EFAULT; + rcu_read_unlock(); + iput(inode); + + goto out; + } + key->both.offset |= FUT_OFF_INODE; /* inode-based key */ - key->shared.inode = page_head->mapping->host; + key->shared.inode = inode; key->shared.pgoff = basepage_index(page); + rcu_read_unlock(); } - get_futex_key_refs(key); /* implies MB (B) */ - out: - unlock_page(page_head); put_page(page_head); return err; } From 36fe96f8010478017d23fa0a6335cef285f07759 Mon Sep 17 00:00:00 2001 From: Jianyu Zhan Date: Mon, 7 Mar 2016 09:32:24 +0800 Subject: [PATCH 246/392] futex: Replace barrier() in unqueue_me() with READ_ONCE() commit 29b75eb2d56a714190a93d7be4525e617591077a upstream. Commit e91467ecd1ef ("bug in futex unqueue_me") introduced a barrier() in unqueue_me() to prevent the compiler from rereading the lock pointer which might change after a check for NULL. Replace the barrier() with a READ_ONCE() for the following reasons: 1) READ_ONCE() is a weaker form of barrier() that affects only the specific load operation, while barrier() is a general compiler level memory barrier. READ_ONCE() was not available at the time when the barrier was added. 2) Aside of that READ_ONCE() is descriptive and self explainatory while a barrier without comment is not clear to the casual reader. No functional change. [ tglx: Massaged changelog ] Change-Id: I41b0f0c77dc827536685dddb60f32a31c1cde559 Signed-off-by: Jianyu Zhan Acked-by: Christian Borntraeger Acked-by: Darren Hart Cc: dave@stgolabs.net Cc: peterz@infradead.org Cc: linux@rasmusvillemoes.dk Cc: akpm@linux-foundation.org Cc: fengguang.wu@intel.com Cc: bigeasy@linutronix.de Link: http://lkml.kernel.org/r/1457314344-5685-1-git-send-email-nasa4836@gmail.com Signed-off-by: Thomas Gleixner Signed-off-by: Davidlohr Bueso Signed-off-by: Greg Kroah-Hartman Git-repo: https://android.googlesource.com/kernel/msm Git-commit: 1920b8a6a6ed80d3a595ff718c0a99c7d4d895c4 Signed-off-by: Srinivasa Rao Kuppala --- kernel/futex.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index e75c3c414af5..55e87606f80b 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1918,8 +1918,12 @@ static int unqueue_me(struct futex_q *q) /* In the common case we don't take the spinlock, which is nice. */ retry: - lock_ptr = q->lock_ptr; - barrier(); + /* + * q->lock_ptr can change between this read and the following spin_lock. + * Use READ_ONCE to forbid the compiler from reloading q->lock_ptr and + * optimizing lock_ptr out of the logic below. + */ + lock_ptr = READ_ONCE(q->lock_ptr); if (lock_ptr != NULL) { spin_lock(lock_ptr); /* From 63615faa6006e9619a861221b37884b743077370 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Tue, 7 Aug 2018 20:03:57 +0300 Subject: [PATCH 247/392] dccp: fix undefined behavior with 'cwnd' shift in ccid2_cwnd_restart() [ Upstream commit 61ef4b07fcdc30535889990cf4229766502561cf ] The shift of 'cwnd' with '(now - hc->tx_lsndtime) / hc->tx_rto' value can lead to undefined behavior [1]. In order to fix this use a gradual shift of the window with a 'while' loop, similar to what tcp_cwnd_restart() is doing. When comparing delta and RTO there is a minor difference between TCP and DCCP, the last one also invokes dccp_cwnd_restart() and reduces 'cwnd' if delta equals RTO. That case is preserved in this change. [1]: [40850.963623] UBSAN: Undefined behaviour in net/dccp/ccids/ccid2.c:237:7 [40851.043858] shift exponent 67 is too large for 32-bit type 'unsigned int' [40851.127163] CPU: 3 PID: 15940 Comm: netstress Tainted: G W E 4.18.0-rc7.x86_64 #1 ... [40851.377176] Call Trace: [40851.408503] dump_stack+0xf1/0x17b [40851.451331] ? show_regs_print_info+0x5/0x5 [40851.503555] ubsan_epilogue+0x9/0x7c [40851.548363] __ubsan_handle_shift_out_of_bounds+0x25b/0x2b4 [40851.617109] ? __ubsan_handle_load_invalid_value+0x18f/0x18f [40851.686796] ? xfrm4_output_finish+0x80/0x80 [40851.739827] ? lock_downgrade+0x6d0/0x6d0 [40851.789744] ? xfrm4_prepare_output+0x160/0x160 [40851.845912] ? ip_queue_xmit+0x810/0x1db0 [40851.895845] ? ccid2_hc_tx_packet_sent+0xd36/0x10a0 [dccp] [40851.963530] ccid2_hc_tx_packet_sent+0xd36/0x10a0 [dccp] [40852.029063] dccp_xmit_packet+0x1d3/0x720 [dccp] [40852.086254] dccp_write_xmit+0x116/0x1d0 [dccp] [40852.142412] dccp_sendmsg+0x428/0xb20 [dccp] [40852.195454] ? inet_dccp_listen+0x200/0x200 [dccp] [40852.254833] ? sched_clock+0x5/0x10 [40852.298508] ? sched_clock+0x5/0x10 [40852.342194] ? inet_create+0xdf0/0xdf0 [40852.388988] sock_sendmsg+0xd9/0x160 ... Fixes: 113ced1f52e5 ("dccp ccid-2: Perform congestion-window validation") Signed-off-by: Alexey Kodanev Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dccp/ccids/ccid2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 86a2ed0fb219..161dfcf86126 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -228,14 +228,16 @@ static void ccid2_cwnd_restart(struct sock *sk, const u32 now) struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); u32 cwnd = hc->tx_cwnd, restart_cwnd, iwnd = rfc3390_bytes_to_packets(dccp_sk(sk)->dccps_mss_cache); + s32 delta = now - hc->tx_lsndtime; hc->tx_ssthresh = max(hc->tx_ssthresh, (cwnd >> 1) + (cwnd >> 2)); /* don't reduce cwnd below the initial window (IW) */ restart_cwnd = min(cwnd, iwnd); - cwnd >>= (now - hc->tx_lsndtime) / hc->tx_rto; - hc->tx_cwnd = max(cwnd, restart_cwnd); + while ((delta -= hc->tx_rto) >= 0 && cwnd > restart_cwnd) + cwnd >>= 1; + hc->tx_cwnd = max(cwnd, restart_cwnd); hc->tx_cwnd_stamp = now; hc->tx_cwnd_used = 0; From 719710e960a5f6bfa0852ffc1af9ad6bb125511d Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Fri, 10 Aug 2018 11:14:56 -0700 Subject: [PATCH 248/392] l2tp: use sk_dst_check() to avoid race on sk->sk_dst_cache [ Upstream commit 6d37fa49da1e8db8fb1995be22ac837ca41ac8a8 ] In l2tp code, if it is a L2TP_UDP_ENCAP tunnel, tunnel->sk points to a UDP socket. User could call sendmsg() on both this tunnel and the UDP socket itself concurrently. As l2tp_xmit_skb() holds socket lock and call __sk_dst_check() to refresh sk->sk_dst_cache, while udpv6_sendmsg() is lockless and call sk_dst_check() to refresh sk->sk_dst_cache, there could be a race and cause the dst cache to be freed multiple times. So we fix l2tp side code to always call sk_dst_check() to garantee xchg() is called when refreshing sk->sk_dst_cache to avoid race conditions. Syzkaller reported stack trace: BUG: KASAN: use-after-free in atomic_read include/asm-generic/atomic-instrumented.h:21 [inline] BUG: KASAN: use-after-free in atomic_fetch_add_unless include/linux/atomic.h:575 [inline] BUG: KASAN: use-after-free in atomic_add_unless include/linux/atomic.h:597 [inline] BUG: KASAN: use-after-free in dst_hold_safe include/net/dst.h:308 [inline] BUG: KASAN: use-after-free in ip6_hold_safe+0xe6/0x670 net/ipv6/route.c:1029 Read of size 4 at addr ffff8801aea9a880 by task syz-executor129/4829 CPU: 0 PID: 4829 Comm: syz-executor129 Not tainted 4.18.0-rc7-next-20180802+ #30 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1c9/0x2b4 lib/dump_stack.c:113 print_address_description+0x6c/0x20b mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report.cold.7+0x242/0x30d mm/kasan/report.c:412 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x13e/0x1b0 mm/kasan/kasan.c:267 kasan_check_read+0x11/0x20 mm/kasan/kasan.c:272 atomic_read include/asm-generic/atomic-instrumented.h:21 [inline] atomic_fetch_add_unless include/linux/atomic.h:575 [inline] atomic_add_unless include/linux/atomic.h:597 [inline] dst_hold_safe include/net/dst.h:308 [inline] ip6_hold_safe+0xe6/0x670 net/ipv6/route.c:1029 rt6_get_pcpu_route net/ipv6/route.c:1249 [inline] ip6_pol_route+0x354/0xd20 net/ipv6/route.c:1922 ip6_pol_route_output+0x54/0x70 net/ipv6/route.c:2098 fib6_rule_lookup+0x283/0x890 net/ipv6/fib6_rules.c:122 ip6_route_output_flags+0x2c5/0x350 net/ipv6/route.c:2126 ip6_dst_lookup_tail+0x1278/0x1da0 net/ipv6/ip6_output.c:978 ip6_dst_lookup_flow+0xc8/0x270 net/ipv6/ip6_output.c:1079 ip6_sk_dst_lookup_flow+0x5ed/0xc50 net/ipv6/ip6_output.c:1117 udpv6_sendmsg+0x2163/0x36b0 net/ipv6/udp.c:1354 inet_sendmsg+0x1a1/0x690 net/ipv4/af_inet.c:798 sock_sendmsg_nosec net/socket.c:622 [inline] sock_sendmsg+0xd5/0x120 net/socket.c:632 ___sys_sendmsg+0x51d/0x930 net/socket.c:2115 __sys_sendmmsg+0x240/0x6f0 net/socket.c:2210 __do_sys_sendmmsg net/socket.c:2239 [inline] __se_sys_sendmmsg net/socket.c:2236 [inline] __x64_sys_sendmmsg+0x9d/0x100 net/socket.c:2236 do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x446a29 Code: e8 ac b8 02 00 48 83 c4 18 c3 0f 1f 80 00 00 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 eb 08 fc ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007f4de5532db8 EFLAGS: 00000246 ORIG_RAX: 0000000000000133 RAX: ffffffffffffffda RBX: 00000000006dcc38 RCX: 0000000000446a29 RDX: 00000000000000b8 RSI: 0000000020001b00 RDI: 0000000000000003 RBP: 00000000006dcc30 R08: 00007f4de5533700 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000006dcc3c R13: 00007ffe2b830fdf R14: 00007f4de55339c0 R15: 0000000000000001 Fixes: 71b1391a4128 ("l2tp: ensure sk->dst is still valid") Reported-by: syzbot+05f840f3b04f211bad55@syzkaller.appspotmail.com Signed-off-by: Wei Wang Signed-off-by: Martin KaFai Lau Cc: Guillaume Nault Cc: David Ahern Cc: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index b7f19946a78b..9010f9a5b18b 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1141,7 +1141,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len /* Get routing info from the tunnel socket */ skb_dst_drop(skb); - skb_dst_set(skb, dst_clone(__sk_dst_check(sk, 0))); + skb_dst_set(skb, sk_dst_check(sk, 0)); inet = inet_sk(sk); fl = &inet->cork.fl; From 71e6f3f1c911f786c31fdb3be6ca2fc807d3aefa Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Tue, 7 Aug 2018 12:41:38 -0700 Subject: [PATCH 249/392] llc: use refcount_inc_not_zero() for llc_sap_find() [ Upstream commit 0dcb82254d65f72333aa50ad626d1e9665ad093b ] llc_sap_put() decreases the refcnt before deleting sap from the global list. Therefore, there is a chance llc_sap_find() could find a sap with zero refcnt in this global list. Close this race condition by checking if refcnt is zero or not in llc_sap_find(), if it is zero then it is being removed so we can just treat it as gone. Reported-by: Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/llc.h | 5 +++++ net/llc/llc_core.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/net/llc.h b/include/net/llc.h index e8e61d4fb458..82d989995d18 100644 --- a/include/net/llc.h +++ b/include/net/llc.h @@ -116,6 +116,11 @@ static inline void llc_sap_hold(struct llc_sap *sap) atomic_inc(&sap->refcnt); } +static inline bool llc_sap_hold_safe(struct llc_sap *sap) +{ + return atomic_inc_not_zero(&sap->refcnt); +} + void llc_sap_close(struct llc_sap *sap); static inline void llc_sap_put(struct llc_sap *sap) diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index 842851cef698..e896a2c53b12 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c @@ -73,8 +73,8 @@ struct llc_sap *llc_sap_find(unsigned char sap_value) rcu_read_lock_bh(); sap = __llc_sap_find(sap_value); - if (sap) - llc_sap_hold(sap); + if (!sap || !llc_sap_hold_safe(sap)) + sap = NULL; rcu_read_unlock_bh(); return sap; } From 8a6eecdb42454512cd803ddf19646ca8a1d5f996 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Mon, 13 Aug 2018 18:44:04 +0800 Subject: [PATCH 250/392] net_sched: Fix missing res info when create new tc_index filter [ Upstream commit 008369dcc5f7bfba526c98054f8525322acf0ea3 ] Li Shuang reported the following warn: [ 733.484610] WARNING: CPU: 6 PID: 21123 at net/sched/sch_cbq.c:1418 cbq_destroy_class+0x5d/0x70 [sch_cbq] [ 733.495190] Modules linked in: sch_cbq cls_tcindex sch_dsmark rpcsec_gss_krb5 auth_rpcgss nfsv4 dns_resolver nfs lockd grace fscache xt_CHECKSUM iptable_mangle ipt_MASQUERADE iptable_nat l [ 733.574155] syscopyarea sysfillrect sysimgblt fb_sys_fops ttm drm igb ixgbe ahci libahci i2c_algo_bit libata i40e i2c_core dca mdio megaraid_sas dm_mirror dm_region_hash dm_log dm_mod [ 733.592500] CPU: 6 PID: 21123 Comm: tc Not tainted 4.18.0-rc8.latest+ #131 [ 733.600169] Hardware name: Dell Inc. PowerEdge R730/0WCJNT, BIOS 2.1.5 04/11/2016 [ 733.608518] RIP: 0010:cbq_destroy_class+0x5d/0x70 [sch_cbq] [ 733.614734] Code: e7 d9 d2 48 8b 7b 48 e8 61 05 da d2 48 8d bb f8 00 00 00 e8 75 ae d5 d2 48 39 eb 74 0a 48 89 df 5b 5d e9 16 6c 94 d2 5b 5d c3 <0f> 0b eb b6 0f 1f 44 00 00 66 2e 0f 1f 84 [ 733.635798] RSP: 0018:ffffbfbb066bb9d8 EFLAGS: 00010202 [ 733.641627] RAX: 0000000000000001 RBX: ffff9cdd17392800 RCX: 000000008010000f [ 733.649588] RDX: ffff9cdd1df547e0 RSI: ffff9cdd17392800 RDI: ffff9cdd0f84c800 [ 733.657547] RBP: ffff9cdd0f84c800 R08: 0000000000000001 R09: 0000000000000000 [ 733.665508] R10: ffff9cdd0f84d000 R11: 0000000000000001 R12: 0000000000000001 [ 733.673469] R13: 0000000000000000 R14: 0000000000000001 R15: ffff9cdd17392200 [ 733.681430] FS: 00007f911890a740(0000) GS:ffff9cdd1f8c0000(0000) knlGS:0000000000000000 [ 733.690456] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 733.696864] CR2: 0000000000b5544c CR3: 0000000859374002 CR4: 00000000001606e0 [ 733.704826] Call Trace: [ 733.707554] cbq_destroy+0xa1/0xd0 [sch_cbq] [ 733.712318] qdisc_destroy+0x62/0x130 [ 733.716401] dsmark_destroy+0x2a/0x70 [sch_dsmark] [ 733.721745] qdisc_destroy+0x62/0x130 [ 733.725829] qdisc_graft+0x3ba/0x470 [ 733.729817] tc_get_qdisc+0x2a6/0x2c0 [ 733.733901] ? cred_has_capability+0x7d/0x130 [ 733.738761] rtnetlink_rcv_msg+0x263/0x2d0 [ 733.743330] ? rtnl_calcit.isra.30+0x110/0x110 [ 733.748287] netlink_rcv_skb+0x4d/0x130 [ 733.752576] netlink_unicast+0x1a3/0x250 [ 733.756949] netlink_sendmsg+0x2ae/0x3a0 [ 733.761324] sock_sendmsg+0x36/0x40 [ 733.765213] ___sys_sendmsg+0x26f/0x2d0 [ 733.769493] ? handle_pte_fault+0x586/0xdf0 [ 733.774158] ? __handle_mm_fault+0x389/0x500 [ 733.778919] ? __sys_sendmsg+0x5e/0xa0 [ 733.783099] __sys_sendmsg+0x5e/0xa0 [ 733.787087] do_syscall_64+0x5b/0x180 [ 733.791171] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 733.796805] RIP: 0033:0x7f9117f23f10 [ 733.800791] Code: c3 48 8b 05 82 6f 2c 00 f7 db 64 89 18 48 83 cb ff eb dd 0f 1f 80 00 00 00 00 83 3d 8d d0 2c 00 00 75 10 b8 2e 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 [ 733.821873] RSP: 002b:00007ffe96818398 EFLAGS: 00000246 ORIG_RAX: 000000000000002e [ 733.830319] RAX: ffffffffffffffda RBX: 000000005b71244c RCX: 00007f9117f23f10 [ 733.838280] RDX: 0000000000000000 RSI: 00007ffe968183e0 RDI: 0000000000000003 [ 733.846241] RBP: 00007ffe968183e0 R08: 000000000000ffff R09: 0000000000000003 [ 733.854202] R10: 00007ffe96817e20 R11: 0000000000000246 R12: 0000000000000000 [ 733.862161] R13: 0000000000662ee0 R14: 0000000000000000 R15: 0000000000000000 [ 733.870121] ---[ end trace 28edd4aad712ddca ]--- This is because we didn't update f->result.res when create new filter. Then in tcindex_delete() -> tcf_unbind_filter(), we will failed to find out the res and unbind filter, which will trigger the WARN_ON() in cbq_destroy_class(). Fix it by updating f->result.res when create new filter. Fixes: 6e0565697a106 ("net_sched: fix another crash in cls_tcindex") Reported-by: Li Shuang Signed-off-by: Hangbin Liu Acked-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/cls_tcindex.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 30f10fb07f4a..9494b4c040dd 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -384,6 +384,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, struct tcindex_filter *nfp; struct tcindex_filter __rcu **fp; + f->result.res = r->res; tcf_exts_change(tp, &f->result.exts, &r->exts); fp = cp->h + (handle % cp->hash); From 31b912a5bf5adc11d1262c0e22911e3998172296 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Mon, 13 Aug 2018 18:44:03 +0800 Subject: [PATCH 251/392] net_sched: fix NULL pointer dereference when delete tcindex filter [ Upstream commit 2df8bee5654bb2b7312662ca6810d4dc16b0b67f ] Li Shuang reported the following crash: [ 71.267724] BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 [ 71.276456] PGD 800000085d9bd067 P4D 800000085d9bd067 PUD 859a0b067 PMD 0 [ 71.284127] Oops: 0000 [#1] SMP PTI [ 71.288015] CPU: 12 PID: 2386 Comm: tc Not tainted 4.18.0-rc8.latest+ #131 [ 71.295686] Hardware name: Dell Inc. PowerEdge R730/0WCJNT, BIOS 2.1.5 04/11/2016 [ 71.304037] RIP: 0010:tcindex_delete+0x72/0x280 [cls_tcindex] [ 71.310446] Code: 00 31 f6 48 87 75 20 48 85 f6 74 11 48 8b 47 18 48 8b 40 08 48 8b 40 50 e8 fb a6 f8 fc 48 85 db 0f 84 dc 00 00 00 48 8b 73 18 <8b> 56 04 48 8d 7e 04 85 d2 0f 84 7b 01 00 [ 71.331517] RSP: 0018:ffffb45207b3f898 EFLAGS: 00010282 [ 71.337345] RAX: ffff8ad3d72d6360 RBX: ffff8acc84393680 RCX: 000000000000002e [ 71.345306] RDX: ffff8ad3d72c8570 RSI: 0000000000000000 RDI: ffff8ad847a45800 [ 71.353277] RBP: ffff8acc84393688 R08: ffff8ad3d72c8400 R09: 0000000000000000 [ 71.361238] R10: ffff8ad3de786e00 R11: 0000000000000000 R12: ffffb45207b3f8c7 [ 71.369199] R13: ffff8ad3d93bd2a0 R14: 000000000000002e R15: ffff8ad3d72c9600 [ 71.377161] FS: 00007f9d3ec3e740(0000) GS:ffff8ad3df980000(0000) knlGS:0000000000000000 [ 71.386188] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 71.392597] CR2: 0000000000000004 CR3: 0000000852f06003 CR4: 00000000001606e0 [ 71.400558] Call Trace: [ 71.403299] tcindex_destroy_element+0x25/0x40 [cls_tcindex] [ 71.409611] tcindex_walk+0xbb/0x110 [cls_tcindex] [ 71.414953] tcindex_destroy+0x44/0x90 [cls_tcindex] [ 71.420492] ? tcindex_delete+0x280/0x280 [cls_tcindex] [ 71.426323] tcf_proto_destroy+0x16/0x40 [ 71.430696] tcf_chain_flush+0x51/0x70 [ 71.434876] tcf_block_put_ext.part.30+0x8f/0x1b0 [ 71.440122] tcf_block_put+0x4d/0x70 [ 71.444108] cbq_destroy+0x4d/0xd0 [sch_cbq] [ 71.448869] qdisc_destroy+0x62/0x130 [ 71.452951] dsmark_destroy+0x2a/0x70 [sch_dsmark] [ 71.458300] qdisc_destroy+0x62/0x130 [ 71.462373] qdisc_graft+0x3ba/0x470 [ 71.466359] tc_get_qdisc+0x2a6/0x2c0 [ 71.470443] ? cred_has_capability+0x7d/0x130 [ 71.475307] rtnetlink_rcv_msg+0x263/0x2d0 [ 71.479875] ? rtnl_calcit.isra.30+0x110/0x110 [ 71.484832] netlink_rcv_skb+0x4d/0x130 [ 71.489109] netlink_unicast+0x1a3/0x250 [ 71.493482] netlink_sendmsg+0x2ae/0x3a0 [ 71.497859] sock_sendmsg+0x36/0x40 [ 71.501748] ___sys_sendmsg+0x26f/0x2d0 [ 71.506029] ? handle_pte_fault+0x586/0xdf0 [ 71.510694] ? __handle_mm_fault+0x389/0x500 [ 71.515457] ? __sys_sendmsg+0x5e/0xa0 [ 71.519636] __sys_sendmsg+0x5e/0xa0 [ 71.523626] do_syscall_64+0x5b/0x180 [ 71.527711] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 71.533345] RIP: 0033:0x7f9d3e257f10 [ 71.537331] Code: c3 48 8b 05 82 6f 2c 00 f7 db 64 89 18 48 83 cb ff eb dd 0f 1f 80 00 00 00 00 83 3d 8d d0 2c 00 00 75 10 b8 2e 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 [ 71.558401] RSP: 002b:00007fff6f893398 EFLAGS: 00000246 ORIG_RAX: 000000000000002e [ 71.566848] RAX: ffffffffffffffda RBX: 000000005b71274d RCX: 00007f9d3e257f10 [ 71.574810] RDX: 0000000000000000 RSI: 00007fff6f8933e0 RDI: 0000000000000003 [ 71.582770] RBP: 00007fff6f8933e0 R08: 000000000000ffff R09: 0000000000000003 [ 71.590729] R10: 00007fff6f892e20 R11: 0000000000000246 R12: 0000000000000000 [ 71.598689] R13: 0000000000662ee0 R14: 0000000000000000 R15: 0000000000000000 [ 71.606651] Modules linked in: sch_cbq cls_tcindex sch_dsmark xt_CHECKSUM iptable_mangle ipt_MASQUERADE iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_coni [ 71.685425] libahci i2c_algo_bit i2c_core i40e libata dca mdio megaraid_sas dm_mirror dm_region_hash dm_log dm_mod [ 71.697075] CR2: 0000000000000004 [ 71.700792] ---[ end trace f604eb1acacd978b ]--- Reproducer: tc qdisc add dev lo handle 1:0 root dsmark indices 64 set_tc_index tc filter add dev lo parent 1:0 protocol ip prio 1 tcindex mask 0xfc shift 2 tc qdisc add dev lo parent 1:0 handle 2:0 cbq bandwidth 10Mbit cell 8 avpkt 1000 mpu 64 tc class add dev lo parent 2:0 classid 2:1 cbq bandwidth 10Mbit rate 1500Kbit avpkt 1000 prio 1 bounded isolated allot 1514 weight 1 maxburst 10 tc filter add dev lo parent 2:0 protocol ip prio 1 handle 0x2e tcindex classid 2:1 pass_on tc qdisc add dev lo parent 2:1 pfifo limit 5 tc qdisc del dev lo root This is because in tcindex_set_parms, when there is no old_r, we set new exts to cr.exts. And we didn't set it to filter when r == &new_filter_result. Then in tcindex_delete() -> tcf_exts_get_net(), we will get NULL pointer dereference as we didn't init exts. Fix it by moving tcf_exts_change() after "if (old_r && old_r != r)" check. Then we don't need "cr" as there is no errout after that. Fixes: bf63ac73b3e13 ("net_sched: fix an oops in tcindex filter") Reported-by: Li Shuang Signed-off-by: Hangbin Liu Acked-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/cls_tcindex.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 9494b4c040dd..30ec75976d29 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -368,16 +368,13 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, tcf_bind_filter(tp, &cr.res, base); } - if (old_r) - tcf_exts_change(tp, &r->exts, &e); - else - tcf_exts_change(tp, &cr.exts, &e); - if (old_r && old_r != r) tcindex_filter_result_init(old_r); oldp = p; r->res = cr.res; + tcf_exts_change(tp, &r->exts, &e); + rcu_assign_pointer(tp->root, cp); if (r == &new_filter_result) { From 2ccea620f2b5a9dd663ce482d601d7169ef4bb52 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Mon, 6 Aug 2018 11:06:02 -0700 Subject: [PATCH 252/392] vsock: split dwork to avoid reinitializations [ Upstream commit 455f05ecd2b219e9a216050796d30c830d9bc393 ] syzbot reported that we reinitialize an active delayed work in vsock_stream_connect(): ODEBUG: init active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x90 kernel/workqueue.c:1414 WARNING: CPU: 1 PID: 11518 at lib/debugobjects.c:329 debug_print_object+0x16a/0x210 lib/debugobjects.c:326 The pattern is apparently wrong, we should only initialize the dealyed work once and could repeatly schedule it. So we have to move out the initializations to allocation side. And to avoid confusion, we can split the shared dwork into two, instead of re-using the same one. Fixes: d021c344051a ("VSOCK: Introduce VM Sockets") Reported-by: Cc: Andy king Cc: Stefan Hajnoczi Cc: Jorgen Hansen Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/af_vsock.h | 4 ++-- net/vmw_vsock/af_vsock.c | 15 ++++++++------- net/vmw_vsock/vmci_transport.c | 3 +-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index 428277869400..8f9f676f1e16 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -59,7 +59,8 @@ struct vsock_sock { struct list_head pending_links; struct list_head accept_queue; bool rejected; - struct delayed_work dwork; + struct delayed_work connect_work; + struct delayed_work pending_work; u32 peer_shutdown; bool sent_request; bool ignore_connecting_rst; @@ -70,7 +71,6 @@ struct vsock_sock { s64 vsock_stream_has_data(struct vsock_sock *vsk); s64 vsock_stream_has_space(struct vsock_sock *vsk); -void vsock_pending_work(struct work_struct *work); struct sock *__vsock_create(struct net *net, struct socket *sock, struct sock *parent, diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index e8d3313ea2c9..b1c9741d5da8 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -431,14 +431,14 @@ static int vsock_send_shutdown(struct sock *sk, int mode) return transport->shutdown(vsock_sk(sk), mode); } -void vsock_pending_work(struct work_struct *work) +static void vsock_pending_work(struct work_struct *work) { struct sock *sk; struct sock *listener; struct vsock_sock *vsk; bool cleanup; - vsk = container_of(work, struct vsock_sock, dwork.work); + vsk = container_of(work, struct vsock_sock, pending_work.work); sk = sk_vsock(vsk); listener = vsk->listener; cleanup = true; @@ -478,7 +478,6 @@ void vsock_pending_work(struct work_struct *work) sock_put(sk); sock_put(listener); } -EXPORT_SYMBOL_GPL(vsock_pending_work); /**** SOCKET OPERATIONS ****/ @@ -577,6 +576,8 @@ static int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr) return retval; } +static void vsock_connect_timeout(struct work_struct *work); + struct sock *__vsock_create(struct net *net, struct socket *sock, struct sock *parent, @@ -618,6 +619,8 @@ struct sock *__vsock_create(struct net *net, vsk->sent_request = false; vsk->ignore_connecting_rst = false; vsk->peer_shutdown = 0; + INIT_DELAYED_WORK(&vsk->connect_work, vsock_connect_timeout); + INIT_DELAYED_WORK(&vsk->pending_work, vsock_pending_work); psk = parent ? vsock_sk(parent) : NULL; if (parent) { @@ -1095,7 +1098,7 @@ static void vsock_connect_timeout(struct work_struct *work) struct sock *sk; struct vsock_sock *vsk; - vsk = container_of(work, struct vsock_sock, dwork.work); + vsk = container_of(work, struct vsock_sock, connect_work.work); sk = sk_vsock(vsk); lock_sock(sk); @@ -1196,9 +1199,7 @@ static int vsock_stream_connect(struct socket *sock, struct sockaddr *addr, * timeout fires. */ sock_hold(sk); - INIT_DELAYED_WORK(&vsk->dwork, - vsock_connect_timeout); - schedule_delayed_work(&vsk->dwork, timeout); + schedule_delayed_work(&vsk->connect_work, timeout); /* Skip ahead to preserve error code set above. */ goto out_wait; diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index 9bb63ffec4f2..88ed7cf8eda6 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -1127,8 +1127,7 @@ static int vmci_transport_recv_listen(struct sock *sk, vpending->listener = sk; sock_hold(sk); sock_hold(pending); - INIT_DELAYED_WORK(&vpending->dwork, vsock_pending_work); - schedule_delayed_work(&vpending->dwork, HZ); + schedule_delayed_work(&vpending->pending_work, HZ); out: return err; From 9c09519189cd25fc14daafa806d2934bc54aab63 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 Jul 2018 17:10:11 +0200 Subject: [PATCH 253/392] ALSA: vx222: Fix invalid endian conversions commit fff71a4c050ba46e305d910c837b99ba1728135e upstream. The endian conversions used in vx2_dma_read() and vx2_dma_write() are superfluous and even wrong on big-endian machines, as inl() and outl() already do conversions. Kill them. Spotted by sparse, a warning like: sound/pci/vx222/vx222_ops.c:278:30: warning: incorrect type in argument 1 (different base types) Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/vx222/vx222_ops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 5c541ed723dd..5c7fbf403451 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -270,7 +270,7 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime, length >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ for (; length > 0; length--) { - outl(cpu_to_le32(*addr), port); + outl(*addr, port); addr++; } addr = (u32 *)runtime->dma_area; @@ -280,7 +280,7 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime, count >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ for (; count > 0; count--) { - outl(cpu_to_le32(*addr), port); + outl(*addr, port); addr++; } @@ -308,7 +308,7 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime, length >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ for (; length > 0; length--) - *addr++ = le32_to_cpu(inl(port)); + *addr++ = inl(port); addr = (u32 *)runtime->dma_area; pipe->hw_ptr = 0; } @@ -316,7 +316,7 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime, count >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ for (; count > 0; count--) - *addr++ = le32_to_cpu(inl(port)); + *addr++ = inl(port); vx2_release_pseudo_dma(chip); } From 75890e92961f7ea2085f07f295653ec83c56380c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jul 2018 14:27:59 +0200 Subject: [PATCH 254/392] ALSA: virmidi: Fix too long output trigger loop commit 50e9ffb1996a5d11ff5040a266585bad4ceeca0a upstream. The virmidi output trigger tries to parse the all available bytes and process sequencer events as much as possible. In a normal situation, this is supposed to be relatively short, but a program may give a huge buffer and it'll take a long time in a single spin lock, which may eventually lead to a soft lockup. This patch simply adds a workaround, a cond_resched() call in the loop if applicable. A better solution would be to move the event processor into a work, but let's put a duct-tape quickly at first. Reported-and-tested-by: Dae R. Jeong Reported-by: syzbot+619d9f40141d826b097e@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/seq_virmidi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index ef494ffc1369..975a7c939d2f 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -163,6 +163,7 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int count, res; unsigned char buf[32], *pbuf; unsigned long flags; + bool check_resched = !in_atomic(); if (up) { vmidi->trigger = 1; @@ -200,6 +201,15 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, vmidi->event.type = SNDRV_SEQ_EVENT_NONE; } } + if (!check_resched) + continue; + /* do temporary unlock & cond_resched() for avoiding + * CPU soft lockup, which may happen via a write from + * a huge rawmidi buffer + */ + spin_unlock_irqrestore(&substream->runtime->lock, flags); + cond_resched(); + spin_lock_irqsave(&substream->runtime->lock, flags); } out: spin_unlock_irqrestore(&substream->runtime->lock, flags); From 88c9ef778060dd4e5e6ebfd150e8769187523017 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 Jul 2018 17:59:26 +0200 Subject: [PATCH 255/392] ALSA: cs5535audio: Fix invalid endian conversion commit 69756930f2de0457d51db7d505a1e4f40e9fd116 upstream. One place in cs5535audio_build_dma_packets() does an extra conversion via cpu_to_le32(); namely jmpprd_addr is passed to setup_prd() ops, which writes the value via cs_writel(). That is, the callback does the conversion by itself, and we don't need to convert beforehand. This patch fixes that bogus conversion. Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/cs5535audio/cs5535audio.h | 6 +++--- sound/pci/cs5535audio/cs5535audio_pcm.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 0579daa62215..425d1b664029 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -66,9 +66,9 @@ struct cs5535audio_dma_ops { }; struct cs5535audio_dma_desc { - u32 addr; - u16 size; - u16 ctlreserved; + __le32 addr; + __le16 size; + __le16 ctlreserved; }; struct cs5535audio_dma { diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 9c2dc911d8d7..709f1c584d3e 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -158,8 +158,8 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au, lastdesc->addr = cpu_to_le32((u32) dma->desc_buf.addr); lastdesc->size = 0; lastdesc->ctlreserved = cpu_to_le16(PRD_JMP); - jmpprd_addr = cpu_to_le32(lastdesc->addr + - (sizeof(struct cs5535audio_dma_desc)*periods)); + jmpprd_addr = (u32)dma->desc_buf.addr + + sizeof(struct cs5535audio_dma_desc) * periods; dma->substream = substream; dma->period_bytes = period_bytes; From 270ba2ca0a7746ee4ee2295a18616faf5c053a1c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Jul 2018 11:01:04 +0200 Subject: [PATCH 256/392] ALSA: memalloc: Don't exceed over the requested size commit dfef01e150824b0e6da750cacda8958188d29aea upstream. snd_dma_alloc_pages_fallback() tries to allocate pages again when the allocation fails with reduced size. But the first try actually *increases* the size to power-of-two, which may give back a larger chunk than the requested size. This confuses the callers, e.g. sgbuf assumes that the size is equal or less, and it may result in a bad loop due to the underflow and eventually lead to Oops. The code of this function seems incorrectly assuming the usage of get_order(). We need to decrease at first, then align to power-of-two. Reported-and-tested-by: he, bo Reported-by: zhang jun Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/memalloc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 082509eb805d..c5fc489de26f 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -239,16 +239,12 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, int err; while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) { - size_t aligned_size; if (err != -ENOMEM) return err; if (size <= PAGE_SIZE) return -ENOMEM; - aligned_size = PAGE_SIZE << get_order(size); - if (size != aligned_size) - size = aligned_size; - else - size >>= 1; + size >>= 1; + size = PAGE_SIZE << get_order(size); } if (! dmab->area) return -ENOMEM; From 23a5e857061deef890fcdf341f98cb0eaf1a970d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 Jul 2018 17:11:38 +0200 Subject: [PATCH 257/392] ALSA: vxpocket: Fix invalid endian conversions commit 3acd3e3bab95ec3622ff98da313290ee823a0f68 upstream. The endian conversions used in vxp_dma_read() and vxp_dma_write() are superfluous and even wrong on big-endian machines, as inw() and outw() already do conversions. Kill them. Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pcmcia/vx/vxp_ops.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c index 56aa1ba73ccc..49a883341eff 100644 --- a/sound/pcmcia/vx/vxp_ops.c +++ b/sound/pcmcia/vx/vxp_ops.c @@ -375,7 +375,7 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime, length >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ for (; length > 0; length--) { - outw(cpu_to_le16(*addr), port); + outw(*addr, port); addr++; } addr = (unsigned short *)runtime->dma_area; @@ -385,7 +385,7 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime, count >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ for (; count > 0; count--) { - outw(cpu_to_le16(*addr), port); + outw(*addr, port); addr++; } vx_release_pseudo_dma(chip); @@ -417,7 +417,7 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime, length >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ for (; length > 0; length--) - *addr++ = le16_to_cpu(inw(port)); + *addr++ = inw(port); addr = (unsigned short *)runtime->dma_area; pipe->hw_ptr = 0; } @@ -425,12 +425,12 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime, count >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ for (; count > 1; count--) - *addr++ = le16_to_cpu(inw(port)); + *addr++ = inw(port); /* Disable DMA */ pchip->regDIALOG &= ~VXP_DLG_DMAREAD_SEL_MASK; vx_outb(chip, DIALOG, pchip->regDIALOG); /* Read the last word (16 bits) */ - *addr = le16_to_cpu(inw(port)); + *addr = inw(port); /* Disable 16-bit accesses */ pchip->regDIALOG &= ~VXP_DLG_DMA16_SEL_MASK; vx_outb(chip, DIALOG, pchip->regDIALOG); From 382627a4da357d169e7a2011970d76273dec39fe Mon Sep 17 00:00:00 2001 From: John Ogness Date: Sun, 24 Jun 2018 00:32:11 +0200 Subject: [PATCH 258/392] USB: serial: sierra: fix potential deadlock at close commit e60870012e5a35b1506d7b376fddfb30e9da0b27 upstream. The portdata spinlock can be taken in interrupt context (via sierra_outdat_callback()). Disable interrupts when taking the portdata spinlock when discarding deferred URBs during close to prevent a possible deadlock. Fixes: 014333f77c0b ("USB: sierra: fix urb and memory leak on disconnect") Cc: stable Signed-off-by: John Ogness Signed-off-by: Sebastian Andrzej Siewior [ johan: amend commit message and add fixes and stable tags ] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 07d1ecd564f7..8960a46c83bb 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -790,9 +790,9 @@ static void sierra_close(struct usb_serial_port *port) kfree(urb->transfer_buffer); usb_free_urb(urb); usb_autopm_put_interface_async(serial->interface); - spin_lock(&portdata->lock); + spin_lock_irq(&portdata->lock); portdata->outstanding_urbs--; - spin_unlock(&portdata->lock); + spin_unlock_irq(&portdata->lock); } sierra_stop_rx_urbs(port); From 0af583b905e3845fbfa140ac4dac466d8c25c8fd Mon Sep 17 00:00:00 2001 From: Chen Hu Date: Fri, 27 Jul 2018 18:32:41 +0800 Subject: [PATCH 259/392] serial: 8250_dw: always set baud rate in dw8250_set_termios commit dfcab6ba573445c703235ab6c83758eec12d7f28 upstream. dw8250_set_termios() doesn't set baud rate if the arg "old ktermios" is NULL. This happens during resume. Call Trace: ... [ 54.928108] dw8250_set_termios+0x162/0x170 [ 54.928114] serial8250_set_termios+0x17/0x20 [ 54.928117] uart_change_speed+0x64/0x160 [ 54.928119] uart_resume_port ... So the baud rate is not restored after S3 and breaks the apps who use UART, for example, console and bluetooth etc. We address this issue by setting the baud rate irrespective of arg "old", just like the drivers for other 8250 IPs. This is tested with Intel Broxton platform. Signed-off-by: Chen Hu Fixes: 4e26b134bd17 ("serial: 8250_dw: clock rate handling for all ACPI platforms") Cc: Heikki Krogerus Cc: stable Reviewed-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 5c247d7943aa..077e0667bbf8 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -202,7 +202,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, unsigned int rate; int ret; - if (IS_ERR(d->clk) || !old) + if (IS_ERR(d->clk)) goto out; /* Not requesting clock rates below 1.8432Mhz */ From 9515219e9402dbc91e8a9be51dab10880a326c0a Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Sun, 15 Jul 2018 20:36:50 +0100 Subject: [PATCH 260/392] Bluetooth: avoid killing an already killed socket commit 4e1a720d0312fd510699032c7694a362a010170f upstream. slub debug reported: [ 440.648642] ============================================================================= [ 440.648649] BUG kmalloc-1024 (Tainted: G BU O ): Poison overwritten [ 440.648651] ----------------------------------------------------------------------------- [ 440.648655] INFO: 0xe70f4bec-0xe70f4bec. First byte 0x6a instead of 0x6b [ 440.648665] INFO: Allocated in sk_prot_alloc+0x6b/0xc6 age=33155 cpu=1 pid=1047 [ 440.648671] ___slab_alloc.constprop.24+0x1fc/0x292 [ 440.648675] __slab_alloc.isra.18.constprop.23+0x1c/0x25 [ 440.648677] __kmalloc+0xb6/0x17f [ 440.648680] sk_prot_alloc+0x6b/0xc6 [ 440.648683] sk_alloc+0x1e/0xa1 [ 440.648700] sco_sock_alloc.constprop.6+0x26/0xaf [bluetooth] [ 440.648716] sco_connect_cfm+0x166/0x281 [bluetooth] [ 440.648731] hci_conn_request_evt.isra.53+0x258/0x281 [bluetooth] [ 440.648746] hci_event_packet+0x28b/0x2326 [bluetooth] [ 440.648759] hci_rx_work+0x161/0x291 [bluetooth] [ 440.648764] process_one_work+0x163/0x2b2 [ 440.648767] worker_thread+0x1a9/0x25c [ 440.648770] kthread+0xf8/0xfd [ 440.648774] ret_from_fork+0x2e/0x38 [ 440.648779] INFO: Freed in __sk_destruct+0xd3/0xdf age=3815 cpu=1 pid=1047 [ 440.648782] __slab_free+0x4b/0x27a [ 440.648784] kfree+0x12e/0x155 [ 440.648787] __sk_destruct+0xd3/0xdf [ 440.648790] sk_destruct+0x27/0x29 [ 440.648793] __sk_free+0x75/0x91 [ 440.648795] sk_free+0x1c/0x1e [ 440.648810] sco_sock_kill+0x5a/0x5f [bluetooth] [ 440.648825] sco_conn_del+0x8e/0xba [bluetooth] [ 440.648840] sco_disconn_cfm+0x3a/0x41 [bluetooth] [ 440.648855] hci_event_packet+0x45e/0x2326 [bluetooth] [ 440.648868] hci_rx_work+0x161/0x291 [bluetooth] [ 440.648872] process_one_work+0x163/0x2b2 [ 440.648875] worker_thread+0x1a9/0x25c [ 440.648877] kthread+0xf8/0xfd [ 440.648880] ret_from_fork+0x2e/0x38 [ 440.648884] INFO: Slab 0xf4718580 objects=27 used=27 fp=0x (null) flags=0x40008100 [ 440.648886] INFO: Object 0xe70f4b88 @offset=19336 fp=0xe70f54f8 When KASAN was enabled, it reported: [ 210.096613] ================================================================== [ 210.096634] BUG: KASAN: use-after-free in ex_handler_refcount+0x5b/0x127 [ 210.096641] Write of size 4 at addr ffff880107e17160 by task kworker/u9:1/2040 [ 210.096651] CPU: 1 PID: 2040 Comm: kworker/u9:1 Tainted: G U O 4.14.47-20180606+ #2 [ 210.096654] Hardware name: , BIOS 2017.01-00087-g43e04de 08/30/2017 [ 210.096693] Workqueue: hci0 hci_rx_work [bluetooth] [ 210.096698] Call Trace: [ 210.096711] dump_stack+0x46/0x59 [ 210.096722] print_address_description+0x6b/0x23b [ 210.096729] ? ex_handler_refcount+0x5b/0x127 [ 210.096736] kasan_report+0x220/0x246 [ 210.096744] ex_handler_refcount+0x5b/0x127 [ 210.096751] ? ex_handler_clear_fs+0x85/0x85 [ 210.096757] fixup_exception+0x8c/0x96 [ 210.096766] do_trap+0x66/0x2c1 [ 210.096773] do_error_trap+0x152/0x180 [ 210.096781] ? fixup_bug+0x78/0x78 [ 210.096817] ? hci_debugfs_create_conn+0x244/0x26a [bluetooth] [ 210.096824] ? __schedule+0x113b/0x1453 [ 210.096830] ? sysctl_net_exit+0xe/0xe [ 210.096837] ? __wake_up_common+0x343/0x343 [ 210.096843] ? insert_work+0x107/0x163 [ 210.096850] invalid_op+0x1b/0x40 [ 210.096888] RIP: 0010:hci_debugfs_create_conn+0x244/0x26a [bluetooth] [ 210.096892] RSP: 0018:ffff880094a0f970 EFLAGS: 00010296 [ 210.096898] RAX: 0000000000000000 RBX: ffff880107e170e8 RCX: ffff880107e17160 [ 210.096902] RDX: 000000000000002f RSI: ffff88013b80ed40 RDI: ffffffffa058b940 [ 210.096906] RBP: ffff88011b2b0578 R08: 00000000852f0ec9 R09: ffffffff81cfcf9b [ 210.096909] R10: 00000000d21bdad7 R11: 0000000000000001 R12: ffff8800967b0488 [ 210.096913] R13: ffff880107e17168 R14: 0000000000000068 R15: ffff8800949c0008 [ 210.096920] ? __sk_destruct+0x2c6/0x2d4 [ 210.096959] hci_event_packet+0xff5/0x7de2 [bluetooth] [ 210.096969] ? __local_bh_enable_ip+0x43/0x5b [ 210.097004] ? l2cap_sock_recv_cb+0x158/0x166 [bluetooth] [ 210.097039] ? hci_le_meta_evt+0x2bb3/0x2bb3 [bluetooth] [ 210.097075] ? l2cap_ertm_init+0x94e/0x94e [bluetooth] [ 210.097093] ? xhci_urb_enqueue+0xbd8/0xcf5 [xhci_hcd] [ 210.097102] ? __accumulate_pelt_segments+0x24/0x33 [ 210.097109] ? __accumulate_pelt_segments+0x24/0x33 [ 210.097115] ? __update_load_avg_se.isra.2+0x217/0x3a4 [ 210.097122] ? set_next_entity+0x7c3/0x12cd [ 210.097128] ? pick_next_entity+0x25e/0x26c [ 210.097135] ? pick_next_task_fair+0x2ca/0xc1a [ 210.097141] ? switch_mm_irqs_off+0x346/0xb4f [ 210.097147] ? __switch_to+0x769/0xbc4 [ 210.097153] ? compat_start_thread+0x66/0x66 [ 210.097188] ? hci_conn_check_link_mode+0x1cd/0x1cd [bluetooth] [ 210.097195] ? finish_task_switch+0x392/0x431 [ 210.097228] ? hci_rx_work+0x154/0x487 [bluetooth] [ 210.097260] hci_rx_work+0x154/0x487 [bluetooth] [ 210.097269] process_one_work+0x579/0x9e9 [ 210.097277] worker_thread+0x68f/0x804 [ 210.097285] kthread+0x31c/0x32b [ 210.097292] ? rescuer_thread+0x70c/0x70c [ 210.097299] ? kthread_create_on_node+0xa3/0xa3 [ 210.097306] ret_from_fork+0x35/0x40 [ 210.097314] Allocated by task 2040: [ 210.097323] kasan_kmalloc.part.1+0x51/0xc7 [ 210.097328] __kmalloc+0x17f/0x1b6 [ 210.097335] sk_prot_alloc+0xf2/0x1a3 [ 210.097340] sk_alloc+0x22/0x297 [ 210.097375] sco_sock_alloc.constprop.7+0x23/0x202 [bluetooth] [ 210.097410] sco_connect_cfm+0x2d0/0x566 [bluetooth] [ 210.097443] hci_conn_request_evt.isra.53+0x6d3/0x762 [bluetooth] [ 210.097476] hci_event_packet+0x85e/0x7de2 [bluetooth] [ 210.097507] hci_rx_work+0x154/0x487 [bluetooth] [ 210.097512] process_one_work+0x579/0x9e9 [ 210.097517] worker_thread+0x68f/0x804 [ 210.097523] kthread+0x31c/0x32b [ 210.097529] ret_from_fork+0x35/0x40 [ 210.097533] Freed by task 2040: [ 210.097539] kasan_slab_free+0xb3/0x15e [ 210.097544] kfree+0x103/0x1a9 [ 210.097549] __sk_destruct+0x2c6/0x2d4 [ 210.097584] sco_conn_del.isra.1+0xba/0x10e [bluetooth] [ 210.097617] hci_event_packet+0xff5/0x7de2 [bluetooth] [ 210.097648] hci_rx_work+0x154/0x487 [bluetooth] [ 210.097653] process_one_work+0x579/0x9e9 [ 210.097658] worker_thread+0x68f/0x804 [ 210.097663] kthread+0x31c/0x32b [ 210.097670] ret_from_fork+0x35/0x40 [ 210.097676] The buggy address belongs to the object at ffff880107e170e8 which belongs to the cache kmalloc-1024 of size 1024 [ 210.097681] The buggy address is located 120 bytes inside of 1024-byte region [ffff880107e170e8, ffff880107e174e8) [ 210.097683] The buggy address belongs to the page: [ 210.097689] page:ffffea00041f8400 count:1 mapcount:0 mapping: (null) index:0xffff880107e15b68 compound_mapcount: 0 [ 210.110194] flags: 0x8000000000008100(slab|head) [ 210.115441] raw: 8000000000008100 0000000000000000 ffff880107e15b68 0000000100170016 [ 210.115448] raw: ffffea0004a47620 ffffea0004b48e20 ffff88013b80ed40 0000000000000000 [ 210.115451] page dumped because: kasan: bad access detected [ 210.115454] Memory state around the buggy address: [ 210.115460] ffff880107e17000: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 210.115465] ffff880107e17080: fc fc fc fc fc fc fc fc fc fc fc fc fc fb fb fb [ 210.115469] >ffff880107e17100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 210.115472] ^ [ 210.115477] ffff880107e17180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 210.115481] ffff880107e17200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 210.115483] ================================================================== And finally when BT_DBG() and ftrace was enabled it showed: <...>-14979 [001] .... 186.104191: sco_sock_kill <-sco_sock_close <...>-14979 [001] .... 186.104191: sco_sock_kill <-sco_sock_release <...>-14979 [001] .... 186.104192: sco_sock_kill: sk ef0497a0 state 9 <...>-14979 [001] .... 186.104193: bt_sock_unlink <-sco_sock_kill kworker/u9:2-792 [001] .... 186.104246: sco_sock_kill <-sco_conn_del kworker/u9:2-792 [001] .... 186.104248: sco_sock_kill: sk ef0497a0 state 9 kworker/u9:2-792 [001] .... 186.104249: bt_sock_unlink <-sco_sock_kill kworker/u9:2-792 [001] .... 186.104250: sco_sock_destruct <-__sk_destruct kworker/u9:2-792 [001] .... 186.104250: sco_sock_destruct: sk ef0497a0 kworker/u9:2-792 [001] .... 186.104860: hci_conn_del <-hci_event_packet kworker/u9:2-792 [001] .... 186.104864: hci_conn_del: hci0 hcon ef0484c0 handle 266 Only in the failed case, sco_sock_kill() gets called with the same sock pointer two times. Add a check for SOCK_DEAD to avoid continue killing a socket which has already been killed. Signed-off-by: Sudip Mukherjee Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/sco.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index b3ef78a644ed..64f3a2f7a2c2 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -390,7 +390,8 @@ static void sco_sock_cleanup_listen(struct sock *parent) */ static void sco_sock_kill(struct sock *sk) { - if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket) + if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket || + sock_flag(sk, SOCK_DEAD)) return; BT_DBG("sk %p state %d", sk, sk->sk_state); From f6d57daec7317c55f04fa19cf58808caf51d3bac Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 15 Aug 2018 12:14:05 -0700 Subject: [PATCH 261/392] isdn: Disable IIOCDBGVAR [ Upstream commit 5e22002aa8809e2efab2da95855f73f63e14a36c ] It was possible to directly leak the kernel address where the isdn_dev structure pointer was stored. This is a kernel ASLR bypass for anyone with access to the ioctl. The code had been present since the beginning of git history, though this shouldn't ever be needed for normal operation, therefore remove it. Reported-by: Al Viro Cc: Karsten Keil Signed-off-by: Kees Cook Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/i4l/isdn_common.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index e4c43a17b333..8088c34336aa 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1655,13 +1655,7 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) } else return -EINVAL; case IIOCDBGVAR: - if (arg) { - if (copy_to_user(argp, &dev, sizeof(ulong))) - return -EFAULT; - return 0; - } else - return -EINVAL; - break; + return -EINVAL; default: if ((cmd & IIOCDRVCTL) == IIOCDRVCTL) cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK; From 20b50fb6ad8f9bd1c0c9adc7c1fcd9f69e54f7ed Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 13 Jun 2018 10:11:56 -0700 Subject: [PATCH 262/392] netfilter: ipv6: nf_defrag: reduce struct net memory waste [ Upstream commit 9ce7bc036ae4cfe3393232c86e9e1fea2153c237 ] It is a waste of memory to use a full "struct netns_sysctl_ipv6" while only one pointer is really used, considering netns_sysctl_ipv6 keeps growing. Also, since "struct netns_frags" has cache line alignment, it is better to move the frags_hdr pointer outside, otherwise we spend a full cache line for this pointer. This saves 192 bytes of memory per netns. Fixes: c038a767cd69 ("ipv6: add a new namespace for nf_conntrack_reasm") Signed-off-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/net/net_namespace.h | 1 + include/net/netns/ipv6.h | 1 - net/ipv6/netfilter/nf_conntrack_reasm.c | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index ff4081af4d9c..7c9518bf0453 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -112,6 +112,7 @@ struct net { #endif #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) struct netns_nf_frag nf_frag; + struct ctl_table_header *nf_frag_frags_hdr; #endif struct sock *nfnl; struct sock *nfnl_stash; diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 69ae41f2098c..c57d055f76bc 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -81,7 +81,6 @@ struct netns_ipv6 { #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) struct netns_nf_frag { - struct netns_sysctl_ipv6 sysctl; struct netns_frags frags; }; #endif diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index d235ed7f47ab..4644d4e2a8bc 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -118,7 +118,7 @@ static int nf_ct_frag6_sysctl_register(struct net *net) if (hdr == NULL) goto err_reg; - net->nf_frag.sysctl.frags_hdr = hdr; + net->nf_frag_frags_hdr = hdr; return 0; err_reg: @@ -132,8 +132,8 @@ static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net) { struct ctl_table *table; - table = net->nf_frag.sysctl.frags_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->nf_frag.sysctl.frags_hdr); + table = net->nf_frag_frags_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->nf_frag_frags_hdr); if (!net_eq(net, &init_net)) kfree(table); } From 3b0134e6309c933a7c38e48506a8c5d0a16b1f6b Mon Sep 17 00:00:00 2001 From: Fathi Boudra Date: Thu, 14 Jun 2018 11:57:08 +0200 Subject: [PATCH 263/392] selftests: sync: add config fragment for testing sync framework [ Upstream commit d6a3e55131fcb1e5ca1753f4b6f297a177b2fc91 ] Unless the software synchronization objects (CONFIG_SW_SYNC) is enabled, the sync test will be skipped: TAP version 13 1..0 # Skipped: Sync framework not supported by kernel Add a config fragment file to be able to run "make kselftest-merge" to enable relevant configuration required in order to run the sync test. Signed-off-by: Fathi Boudra Link: https://lkml.org/lkml/2017/5/5/14 Signed-off-by: Anders Roxell Signed-off-by: Shuah Khan (Samsung OSG) Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/sync/config | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tools/testing/selftests/sync/config diff --git a/tools/testing/selftests/sync/config b/tools/testing/selftests/sync/config new file mode 100644 index 000000000000..1ab7e8130db2 --- /dev/null +++ b/tools/testing/selftests/sync/config @@ -0,0 +1,4 @@ +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y From bd3db434b6f8ef94bc02399266811d587140adb1 Mon Sep 17 00:00:00 2001 From: William Wu Date: Fri, 11 May 2018 17:46:32 +0800 Subject: [PATCH 264/392] usb: dwc2: fix isoc split in transfer with no data [ Upstream commit 70c3c8cb83856758025c2a211dd022bc0478922a ] If isoc split in transfer with no data (the length of DATA0 packet is zero), we can't simply return immediately. Because the DATA0 can be the first transaction or the second transaction for the isoc split in transaction. If the DATA0 packet with no data is in the first transaction, we can return immediately. But if the DATA0 packet with no data is in the second transaction of isoc split in transaction sequence, we need to increase the qtd->isoc_frame_index and giveback urb to device driver if needed, otherwise, the MDATA packet will be lost. A typical test case is that connect the dwc2 controller with an usb hs Hub (GL852G-12), and plug an usb fs audio device (Plantronics headset) into the downstream port of Hub. Then use the usb mic to record, we can find noise when playback. In the case, the isoc split in transaction sequence like this: - SSPLIT IN transaction - CSPLIT IN transaction - MDATA packet (176 bytes) - CSPLIT IN transaction - DATA0 packet (0 byte) This patch use both the length of DATA0 and qtd->isoc_split_offset to check if the DATA0 is in the second transaction. Tested-by: Gevorg Sahakyan Tested-by: Heiko Stuebner Acked-by: Minas Harutyunyan hminas@synopsys.com> Signed-off-by: William Wu Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd_intr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index 551ba878b003..e1675ea36a63 100644 --- a/drivers/usb/dwc2/hcd_intr.c +++ b/drivers/usb/dwc2/hcd_intr.c @@ -913,9 +913,8 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg, frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; len = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd, DWC2_HC_XFER_COMPLETE, NULL); - if (!len) { + if (!len && !qtd->isoc_split_offset) { qtd->complete_split = 0; - qtd->isoc_split_offset = 0; return 0; } From c302a0ec56d6439bc921c2046938a7506515cdfb Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 25 May 2018 17:24:57 +0800 Subject: [PATCH 265/392] usb: gadget: composite: fix delayed_status race condition when set_interface [ Upstream commit 980900d6318066b9f8314bfb87329a20fd0d1ca4 ] It happens when enable debug log, if set_alt() returns USB_GADGET_DELAYED_STATUS and usb_composite_setup_continue() is called before increasing count of @delayed_status, so fix it by using spinlock of @cdev->lock. Signed-off-by: Chunfeng Yun Tested-by: Jay Hsu Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/composite.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 420799614f6a..b20d89bfa4ef 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1530,6 +1530,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; if (w_value && !f->set_alt) break; + + spin_lock(&cdev->lock); value = f->set_alt(f, w_index, w_value); if (value == USB_GADGET_DELAYED_STATUS) { DBG(cdev, @@ -1539,6 +1541,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) DBG(cdev, "delayed_status count %d\n", cdev->delayed_status); } + spin_unlock(&cdev->lock); break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) From f26b61f75b643152f8947b23edb73cadb6863d91 Mon Sep 17 00:00:00 2001 From: Zhizhou Zhang Date: Tue, 12 Jun 2018 17:07:37 +0800 Subject: [PATCH 266/392] arm64: make secondary_start_kernel() notrace [ Upstream commit b154886f7892499d0d3054026e19dfb9a731df61 ] We can't call function trace hook before setup percpu offset. When entering secondary_start_kernel(), percpu offset has not been initialized. So this lead hotplug malfunction. Here is the flow to reproduce this bug: echo 0 > /sys/devices/system/cpu/cpu1/online echo function > /sys/kernel/debug/tracing/current_tracer echo 1 > /sys/kernel/debug/tracing/tracing_on echo 1 > /sys/devices/system/cpu/cpu1/online Acked-by: Mark Rutland Tested-by: Suzuki K Poulose Signed-off-by: Zhizhou Zhang Signed-off-by: Catalin Marinas Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index a1f054549cb6..b53a2e66dfd8 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -130,7 +130,7 @@ static void smp_store_cpu_info(unsigned int cpuid) * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. */ -asmlinkage void secondary_start_kernel(void) +asmlinkage notrace void secondary_start_kernel(void) { struct mm_struct *mm = &init_mm; unsigned int cpu = smp_processor_id(); From 2416eb02d1cede88398149cf9335f14fcd1320bc Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan Date: Tue, 19 Jun 2018 08:15:24 -0700 Subject: [PATCH 267/392] enic: initialize enic->rfs_h.lock in enic_probe [ Upstream commit 3256d29fc7aecdf99feb1cb9475ed2252769a8a7 ] lockdep spotted that we are using rfs_h.lock in enic_get_rxnfc() without initializing. rfs_h.lock is initialized in enic_open(). But ethtool_ops can be called when interface is down. Move enic_rfs_flw_tbl_init to enic_probe. INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 18 PID: 1189 Comm: ethtool Not tainted 4.17.0-rc7-devel+ #27 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-20171110_100015-anatol 04/01/2014 Call Trace: dump_stack+0x85/0xc0 register_lock_class+0x550/0x560 ? __handle_mm_fault+0xa8b/0x1100 __lock_acquire+0x81/0x670 lock_acquire+0xb9/0x1e0 ? enic_get_rxnfc+0x139/0x2b0 [enic] _raw_spin_lock_bh+0x38/0x80 ? enic_get_rxnfc+0x139/0x2b0 [enic] enic_get_rxnfc+0x139/0x2b0 [enic] ethtool_get_rxnfc+0x8d/0x1c0 dev_ethtool+0x16c8/0x2400 ? __mutex_lock+0x64d/0xa00 ? dev_load+0x6a/0x150 dev_ioctl+0x253/0x4b0 sock_do_ioctl+0x9a/0x130 sock_ioctl+0x1af/0x350 do_vfs_ioctl+0x8e/0x670 ? syscall_trace_enter+0x1e2/0x380 ksys_ioctl+0x60/0x90 __x64_sys_ioctl+0x16/0x20 do_syscall_64+0x5a/0x170 entry_SYSCALL_64_after_hwframe+0x49/0xbe Signed-off-by: Govindarajulu Varadarajan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/cisco/enic/enic_clsf.c | 3 +-- drivers/net/ethernet/cisco/enic/enic_main.c | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index 0be6850be8a2..d911a3e94528 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -78,7 +78,6 @@ void enic_rfs_flw_tbl_init(struct enic *enic) enic->rfs_h.max = enic->config.num_arfs; enic->rfs_h.free = enic->rfs_h.max; enic->rfs_h.toclean = 0; - enic_rfs_timer_start(enic); } void enic_rfs_flw_tbl_free(struct enic *enic) @@ -87,7 +86,6 @@ void enic_rfs_flw_tbl_free(struct enic *enic) enic_rfs_timer_stop(enic); spin_lock_bh(&enic->rfs_h.lock); - enic->rfs_h.free = 0; for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) { struct hlist_head *hhead; struct hlist_node *tmp; @@ -98,6 +96,7 @@ void enic_rfs_flw_tbl_free(struct enic *enic) enic_delfltr(enic, n->fltr_id); hlist_del(&n->node); kfree(n); + enic->rfs_h.free++; } } spin_unlock_bh(&enic->rfs_h.lock); diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 14b19aa2125f..aa635cbb648f 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1643,7 +1643,7 @@ static int enic_open(struct net_device *netdev) vnic_intr_unmask(&enic->intr[i]); enic_notify_timer_start(enic); - enic_rfs_flw_tbl_init(enic); + enic_rfs_timer_start(enic); return 0; @@ -2508,6 +2508,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) enic->notify_timer.function = enic_notify_timer; enic->notify_timer.data = (unsigned long)enic; + enic_rfs_flw_tbl_init(enic); enic_set_rx_coal_setting(enic); INIT_WORK(&enic->reset, enic_reset); INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work); From 318b0e847010c28dd8b005379cea48e19ad4b4f1 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sun, 17 Jun 2018 23:40:53 +0200 Subject: [PATCH 268/392] net: hamradio: use eth_broadcast_addr [ Upstream commit 4e8439aa34802deab11cee68b0ecb18f887fb153 ] The array bpq_eth_addr is only used to get the size of an address, whereas the bcast_addr is used to set the broadcast address. This leads to a warning when using clang: drivers/net/hamradio/bpqether.c:94:13: warning: variable 'bpq_eth_addr' is not needed and will not be emitted [-Wunneeded-internal-declaration] static char bpq_eth_addr[6]; ^ Remove both variables and use the common eth_broadcast_addr to set the broadcast address. Signed-off-by: Stefan Agner Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/hamradio/bpqether.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index c2894e43840e..35db4fc691e7 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -90,10 +90,6 @@ static const char banner[] __initconst = KERN_INFO \ "AX.25: bpqether driver version 004\n"; -static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; - -static char bpq_eth_addr[6]; - static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); static int bpq_device_event(struct notifier_block *, unsigned long, void *); @@ -512,8 +508,8 @@ static int bpq_new_device(struct net_device *edev) bpq->ethdev = edev; bpq->axdev = ndev; - memcpy(bpq->dest_addr, bcast_addr, sizeof(bpq_eth_addr)); - memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr)); + eth_broadcast_addr(bpq->dest_addr); + eth_broadcast_addr(bpq->acpt_addr); err = register_netdevice(ndev); if (err) From d4a1dd4e560ec634106aceebf7a8c1de55405941 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Tue, 19 Jun 2018 17:23:17 +0800 Subject: [PATCH 269/392] net: propagate dev_get_valid_name return code [ Upstream commit 7892bd081045222b9e4027fec279a28d6fe7aa66 ] if dev_get_valid_name failed, propagate its return code and remove the setting err to ENODEV, it will be set to 0 again before dev_change_net_namespace exits. Signed-off-by: Li RongQing Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 8bd1e4973d8f..da0b7f3b0517 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6911,7 +6911,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* We get here if we can't use the current device name */ if (!pat) goto out; - if (dev_get_valid_name(net, dev, pat) < 0) + err = dev_get_valid_name(net, dev, pat); + if (err < 0) goto out; } @@ -6923,7 +6924,6 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char dev_close(dev); /* And unlink it from device chain */ - err = -ENODEV; unlist_netdevice(dev); synchronize_net(); From a5eb5cb96d272b194b5bb3a932417e10c2388351 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 20 Jun 2018 10:03:56 +0200 Subject: [PATCH 270/392] net: davinci_emac: match the mdio device against its compatible if possible [ Upstream commit ea0820bb771175c7d4192fc6f5b5c56b3c6d5239 ] Device tree based systems without of_dev_auxdata will have the mdio device named differently than "davinci_mdio(.0)". In this case use the device's parent's compatible string for matching Signed-off-by: Bartosz Golaszewski Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ti/davinci_emac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index ea712512c7d1..03fcce11ea4e 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1514,6 +1514,10 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd) static int match_first_device(struct device *dev, void *data) { + if (dev->parent && dev->parent->of_node) + return of_device_is_compatible(dev->parent->of_node, + "ti,davinci_mdio"); + return !strncmp(dev_name(dev), "davinci_mdio", 12); } From 9773c6dbf97c273b2f7c1d7c41cfa9e3441a3c70 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 4 Apr 2018 14:06:30 -0400 Subject: [PATCH 271/392] locking/lockdep: Do not record IRQ state within lockdep code [ Upstream commit fcc784be837714a9173b372ff9fb9b514590dad9 ] While debugging where things were going wrong with mapping enabling/disabling interrupts with the lockdep state and actual real enabling and disabling interrupts, I had to silent the IRQ disabling/enabling in debug_check_no_locks_freed() because it was always showing up as it was called before the splat was. Use raw_local_irq_save/restore() for not only debug_check_no_locks_freed() but for all internal lockdep functions, as they hide useful information about where interrupts were used incorrectly last. Signed-off-by: Steven Rostedt (VMware) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Link: https://lkml.kernel.org/lkml/20180404140630.3f4f4c7a@gandalf.local.home Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/locking/lockdep.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 3467618cc0ea..f99008534275 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -1253,11 +1253,11 @@ unsigned long lockdep_count_forward_deps(struct lock_class *class) this.parent = NULL; this.class = class; - local_irq_save(flags); + raw_local_irq_save(flags); arch_spin_lock(&lockdep_lock); ret = __lockdep_count_forward_deps(&this); arch_spin_unlock(&lockdep_lock); - local_irq_restore(flags); + raw_local_irq_restore(flags); return ret; } @@ -1280,11 +1280,11 @@ unsigned long lockdep_count_backward_deps(struct lock_class *class) this.parent = NULL; this.class = class; - local_irq_save(flags); + raw_local_irq_save(flags); arch_spin_lock(&lockdep_lock); ret = __lockdep_count_backward_deps(&this); arch_spin_unlock(&lockdep_lock); - local_irq_restore(flags); + raw_local_irq_restore(flags); return ret; } @@ -4083,7 +4083,7 @@ void debug_check_no_locks_freed(const void *mem_from, unsigned long mem_len) if (unlikely(!debug_locks)) return; - local_irq_save(flags); + raw_local_irq_save(flags); for (i = 0; i < curr->lockdep_depth; i++) { hlock = curr->held_locks + i; @@ -4094,7 +4094,7 @@ void debug_check_no_locks_freed(const void *mem_from, unsigned long mem_len) print_freed_lock_bug(curr, mem_from, mem_from + mem_len, hlock); break; } - local_irq_restore(flags); + raw_local_irq_restore(flags); } EXPORT_SYMBOL_GPL(debug_check_no_locks_freed); From 79093b9d5825365aef6975834da656fbf2d713cb Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Thu, 21 Jun 2018 19:49:36 +0800 Subject: [PATCH 272/392] ipv6: mcast: fix unsolicited report interval after receiving querys [ Upstream commit 6c6da92808442908287fae8ebb0ca041a52469f4 ] After recieving MLD querys, we update idev->mc_maxdelay with max_delay from query header. This make the later unsolicited reports have the same interval with mc_maxdelay, which means we may send unsolicited reports with long interval time instead of default configured interval time. Also as we will not call ipv6_mc_reset() after device up. This issue will be there even after leave the group and join other groups. Fixes: fc4eba58b4c14 ("ipv6: make unsolicited report intervals configurable for mld") Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/mcast.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 9cc16fa524a6..5a8c7b764253 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2062,7 +2062,8 @@ void ipv6_mc_dad_complete(struct inet6_dev *idev) mld_send_initial_cr(idev); idev->mc_dad_count--; if (idev->mc_dad_count) - mld_dad_start_timer(idev, idev->mc_maxdelay); + mld_dad_start_timer(idev, + unsolicited_report_interval(idev)); } } @@ -2074,7 +2075,8 @@ static void mld_dad_timer_expire(unsigned long data) if (idev->mc_dad_count) { idev->mc_dad_count--; if (idev->mc_dad_count) - mld_dad_start_timer(idev, idev->mc_maxdelay); + mld_dad_start_timer(idev, + unsolicited_report_interval(idev)); } in6_dev_put(idev); } @@ -2432,7 +2434,8 @@ static void mld_ifc_timer_expire(unsigned long data) if (idev->mc_ifc_count) { idev->mc_ifc_count--; if (idev->mc_ifc_count) - mld_ifc_start_timer(idev, idev->mc_maxdelay); + mld_ifc_start_timer(idev, + unsolicited_report_interval(idev)); } in6_dev_put(idev); } From f1630f80adfc82cddb9d1a0ba984b619ff38f0ec Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Fri, 22 Jun 2018 10:54:45 -0700 Subject: [PATCH 273/392] Smack: Mark inode instant in smack_task_to_inode [ Upstream commit 7b4e88434c4e7982fb053c49657e1c8bbb8692d9 ] Smack: Mark inode instant in smack_task_to_inode /proc clean-up in commit 1bbc55131e59bd099fdc568d3aa0b42634dbd188 resulted in smack_task_to_inode() being called before smack_d_instantiate. This resulted in the smk_inode value being ignored, even while present for files in /proc/self. Marking the inode as instant here fixes that. Signed-off-by: Casey Schaufler Signed-off-by: James Morris Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- security/smack/smack_lsm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index a72b516b319e..59350f6b7e8d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2037,6 +2037,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode) struct smack_known *skp = smk_of_task_struct(p); isp->smk_inode = skp; + isp->smk_flags |= SMK_INODE_INSTANT; } /* From 99b61ce7df0cc3a45c5d2e420dbb70065b1c12e8 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Sat, 23 Jun 2018 20:28:26 +0530 Subject: [PATCH 274/392] cxgb4: when disabling dcb set txq dcb priority to 0 [ Upstream commit 5ce36338a30f9814fc4824f9fe6c20cd83d872c7 ] When we are disabling DCB, store "0" in txq->dcb_prio since that's used for future TX Work Request "OVLAN_IDX" values. Setting non zero priority upon disabling DCB would halt the traffic. Reported-by: AMG Zollner Robert CC: David Ahern Signed-off-by: Casey Leedom Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index a9db2337d9e2..faee5ed88e5c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -529,7 +529,7 @@ static void dcb_tx_queue_prio_enable(struct net_device *dev, int enable) "Can't %s DCB Priority on port %d, TX Queue %d: err=%d\n", enable ? "set" : "unset", pi->port_id, i, -err); else - txq->dcb_prio = value; + txq->dcb_prio = enable ? value : 0; } } #endif /* CONFIG_CHELSIO_T4_DCB */ From 7acdfaef287909094d5871cfdc4c6eed46dfdbf1 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Wed, 30 May 2018 11:06:34 +0200 Subject: [PATCH 275/392] brcmfmac: stop watchdog before detach and free everything [ Upstream commit 373c83a801f15b1e3d02d855fad89112bd4ccbe0 ] Using built-in in kernel image without a firmware in filesystem or in the kernel image can lead to a kernel NULL pointer deference. Watchdog need to be stopped in brcmf_sdio_remove The system is going down NOW! [ 1348.110759] Unable to handle kernel NULL pointer dereference at virtual address 000002f8 Sent SIGTERM to all processes [ 1348.121412] Mem abort info: [ 1348.126962] ESR = 0x96000004 [ 1348.130023] Exception class = DABT (current EL), IL = 32 bits [ 1348.135948] SET = 0, FnV = 0 [ 1348.138997] EA = 0, S1PTW = 0 [ 1348.142154] Data abort info: [ 1348.145045] ISV = 0, ISS = 0x00000004 [ 1348.148884] CM = 0, WnR = 0 [ 1348.151861] user pgtable: 4k pages, 48-bit VAs, pgdp = (____ptrval____) [ 1348.158475] [00000000000002f8] pgd=0000000000000000 [ 1348.163364] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 1348.168927] Modules linked in: ipv6 [ 1348.172421] CPU: 3 PID: 1421 Comm: brcmf_wdog/mmc0 Not tainted 4.17.0-rc5-next-20180517 #18 [ 1348.180757] Hardware name: Amarula A64-Relic (DT) [ 1348.185455] pstate: 60000005 (nZCv daif -PAN -UAO) [ 1348.190251] pc : brcmf_sdiod_freezer_count+0x0/0x20 [ 1348.195124] lr : brcmf_sdio_watchdog_thread+0x64/0x290 [ 1348.200253] sp : ffff00000b85be30 [ 1348.203561] x29: ffff00000b85be30 x28: 0000000000000000 [ 1348.208868] x27: ffff00000b6cb918 x26: ffff80003b990638 [ 1348.214176] x25: ffff0000087b1a20 x24: ffff80003b94f800 [ 1348.219483] x23: ffff000008e620c8 x22: ffff000008f0b660 [ 1348.224790] x21: ffff000008c6a858 x20: 00000000fffffe00 [ 1348.230097] x19: ffff80003b94f800 x18: 0000000000000001 [ 1348.235404] x17: 0000ffffab2e8a74 x16: ffff0000080d7de8 [ 1348.240711] x15: 0000000000000000 x14: 0000000000000400 [ 1348.246018] x13: 0000000000000400 x12: 0000000000000001 [ 1348.251324] x11: 00000000000002c4 x10: 0000000000000a10 [ 1348.256631] x9 : ffff00000b85bc40 x8 : ffff80003be11870 [ 1348.261937] x7 : ffff80003dfc7308 x6 : 000000078ff08b55 [ 1348.267243] x5 : 00000139e1058400 x4 : 0000000000000000 [ 1348.272550] x3 : dead000000000100 x2 : 958f2788d6618100 [ 1348.277856] x1 : 00000000fffffe00 x0 : 0000000000000000 Signed-off-by: Michael Trimarchi Acked-by: Arend van Spriel Tested-by: Andy Shevchenko Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index d20d4e6f391a..f6d35d9a06eb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -4201,6 +4201,13 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) brcmf_dbg(TRACE, "Enter\n"); if (bus) { + /* Stop watchdog task */ + if (bus->watchdog_tsk) { + send_sig(SIGTERM, bus->watchdog_tsk, 1); + kthread_stop(bus->watchdog_tsk); + bus->watchdog_tsk = NULL; + } + /* De-register interrupt handler */ brcmf_sdiod_intr_unregister(bus->sdiodev); From 9b99d54baeceb3e32a1735dbddf389e09d8ba5fe Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sun, 17 Jun 2018 13:53:09 +0200 Subject: [PATCH 276/392] ARM: dts: am437x: make edt-ft5x06 a wakeup source [ Upstream commit 49a6ec5b807ea4ad7ebe1f58080ebb8497cb2d2c ] The touchscreen driver no longer configures the device as wakeup source by default. A "wakeup-source" property is needed. Signed-off-by: Daniel Mack Signed-off-by: Tony Lindgren Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/am437x-sk-evm.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts index 53bbfc90b26a..247ea36407cb 100644 --- a/arch/arm/boot/dts/am437x-sk-evm.dts +++ b/arch/arm/boot/dts/am437x-sk-evm.dts @@ -415,6 +415,8 @@ touchscreen-size-x = <480>; touchscreen-size-y = <272>; + + wakeup-source; }; tlv320aic3106: tlv320aic3106@1b { From 915d80fd2060502aa2301bf6ae4639cb7313b09a Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Mon, 11 Jun 2018 16:10:49 +0530 Subject: [PATCH 277/392] perf report powerpc: Fix crash if callchain is empty [ Upstream commit 143c99f6ac6812d23254e80844d6e34be897d3e1 ] For some cases, the callchain provided by the kernel may be empty. So, the callchain ip filtering code will cause a crash if we do not check whether the struct ip_callchain pointer is NULL before accessing any members. This can be observed on a powerpc64le system running Fedora 27 as shown below. # perf record -b -e cycles:u ls Before: # perf report --branch-history perf: Segmentation fault -------- backtrace -------- perf[0x1027615c] linux-vdso64.so.1(__kernel_sigtramp_rt64+0x0)[0x7fff856304d8] perf(arch_skip_callchain_idx+0x44)[0x10257c58] perf[0x1017f2e4] perf(thread__resolve_callchain+0x124)[0x1017ff5c] perf(sample__resolve_callchain+0xf0)[0x10172788] ... After: # perf report --branch-history Samples: 25 of event 'cycles:u', Event count (approx.): 2306870 Overhead Source:Line Symbol Shared Object + 11.60% _init+35736 [.] _init ls + 9.84% strcoll_l.c:137 [.] __strcoll_l libc-2.26.so + 9.16% memcpy.S:175 [.] __memcpy_power7 libc-2.26.so + 9.01% gconv_charset.h:54 [.] _nl_find_locale libc-2.26.so + 8.87% dl-addr.c:52 [.] _dl_addr libc-2.26.so + 8.83% _init+236 [.] _init ls ... Reported-by: Ravi Bangoria Signed-off-by: Sandipan Das Acked-by: Ravi Bangoria Cc: Jiri Olsa Cc: Naveen N. Rao Cc: Sukadev Bhattiprolu Link: http://lkml.kernel.org/r/20180611104049.11048-1-sandipan@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/arch/powerpc/util/skip-callchain-idx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index d73ef8bb08c7..8e24f39f9158 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c @@ -230,7 +230,7 @@ int arch_skip_callchain_idx(struct machine *machine, struct thread *thread, u64 ip; u64 skip_slot = -1; - if (chain->nr < 3) + if (!chain || chain->nr < 3) return skip_slot; ip = chain->ips[2]; From a750989e3ac47403f470d40dfb47660508d4f334 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 5 Jun 2018 15:37:51 +0530 Subject: [PATCH 278/392] ARM: dts: da850: Fix interrups property for gpio [ Upstream commit 3eb1b955cd7ed1e621ace856710006c2a8a7f231 ] The intc #interrupt-cells is equal to 1. Currently gpio node has 2 cells per IRQ which is wrong. Remove the additional cell for each of the interrupts. Signed-off-by: Keerthy Fixes: 2e38b946dc54 ("ARM: davinci: da850: add GPIO DT node") Signed-off-by: Sekhar Nori Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/da850.dtsi | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi index 0bd98cd00816..4ef5c3410fcc 100644 --- a/arch/arm/boot/dts/da850.dtsi +++ b/arch/arm/boot/dts/da850.dtsi @@ -267,11 +267,7 @@ compatible = "ti,dm6441-gpio"; gpio-controller; reg = <0x226000 0x1000>; - interrupts = <42 IRQ_TYPE_EDGE_BOTH - 43 IRQ_TYPE_EDGE_BOTH 44 IRQ_TYPE_EDGE_BOTH - 45 IRQ_TYPE_EDGE_BOTH 46 IRQ_TYPE_EDGE_BOTH - 47 IRQ_TYPE_EDGE_BOTH 48 IRQ_TYPE_EDGE_BOTH - 49 IRQ_TYPE_EDGE_BOTH 50 IRQ_TYPE_EDGE_BOTH>; + interrupts = <42 43 44 45 46 47 48 49 50>; ti,ngpio = <144>; ti,davinci-gpio-unbanked = <0>; status = "disabled"; From c641c7147ccd5d22727476200d954d75eb1de1e4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 22 Jun 2018 14:15:47 +0300 Subject: [PATCH 279/392] dmaengine: k3dma: Off by one in k3_of_dma_simple_xlate() [ Upstream commit c4c2b7644cc9a41f17a8cc8904efe3f66ae4c7ed ] The d->chans[] array has d->dma_requests elements so the > should be >= here. Fixes: 8e6152bc660e ("dmaengine: Add hisilicon k3 DMA engine driver") Signed-off-by: Dan Carpenter Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/dma/k3dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index a1f911aaf220..a95f46c2a984 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -652,7 +652,7 @@ static struct dma_chan *k3_of_dma_simple_xlate(struct of_phandle_args *dma_spec, struct k3_dma_dev *d = ofdma->of_dma_data; unsigned int request = dma_spec->args[0]; - if (request > d->dma_requests) + if (request >= d->dma_requests) return NULL; return dma_get_slave_channel(&(d->chans[request].vc.chan)); From 0d8e0d1c6fbe3e2868476e1f798a4ef3a66b70cd Mon Sep 17 00:00:00 2001 From: BingJing Chang Date: Thu, 28 Jun 2018 18:40:11 +0800 Subject: [PATCH 280/392] md/raid10: fix that replacement cannot complete recovery after reassemble [ Upstream commit bda3153998f3eb2cafa4a6311971143628eacdbc ] During assemble, the spare marked for replacement is not checked. conf->fullsync cannot be updated to be 1. As a result, recovery will treat it as a clean array. All recovering sectors are skipped. Original device is replaced with the not-recovered spare. mdadm -C /dev/md0 -l10 -n4 -pn2 /dev/loop[0123] mdadm /dev/md0 -a /dev/loop4 mdadm /dev/md0 --replace /dev/loop0 mdadm -S /dev/md0 # stop array during recovery mdadm -A /dev/md0 /dev/loop[01234] After reassemble, you can see recovery go on, but it completes immediately. In fact, recovery is not actually processed. To solve this problem, we just add the missing logics for replacment spares. (In raid1.c or raid5.c, they have already been checked.) Reported-by: Alex Chen Reviewed-by: Alex Wu Reviewed-by: Chung-Chiang Cheng Signed-off-by: BingJing Chang Signed-off-by: Shaohua Li Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid10.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index b19149e45154..bd26567248b3 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -3770,6 +3770,13 @@ static int run(struct mddev *mddev) disk->rdev->saved_raid_disk < 0) conf->fullsync = 1; } + + if (disk->replacement && + !test_bit(In_sync, &disk->replacement->flags) && + disk->replacement->saved_raid_disk < 0) { + conf->fullsync = 1; + } + disk->recovery_disabled = mddev->recovery_disabled - 1; } From f4ed9d9d640b2d80a796fbb24f3723af507100bd Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 7 Jun 2018 13:06:13 +0200 Subject: [PATCH 281/392] drm/exynos: gsc: Fix support for NV16/61, YUV420/YVU420 and YUV422 modes [ Upstream commit dd209ef809080ced903e7747ee3ef640c923a1d2 ] Fix following issues related to planar YUV pixel format configuration: - NV16/61 modes were incorrectly programmed as NV12/21, - YVU420 was programmed as YUV420 on source, - YVU420 and YUV422 were programmed as YUV420 on output. Signed-off-by: Marek Szyprowski Signed-off-by: Inki Dae Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 29 +++++++++++++++++-------- drivers/gpu/drm/exynos/regs-gsc.h | 1 + 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index c6a013fc321c..12d4ac5b19a7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -526,21 +526,25 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt) GSC_IN_CHROMA_ORDER_CRCB); break; case DRM_FORMAT_NV21: + cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_2P); + break; case DRM_FORMAT_NV61: - cfg |= (GSC_IN_CHROMA_ORDER_CRCB | - GSC_IN_YUV420_2P); + cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV422_2P); break; case DRM_FORMAT_YUV422: cfg |= GSC_IN_YUV422_3P; break; case DRM_FORMAT_YUV420: + cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P); + break; case DRM_FORMAT_YVU420: - cfg |= GSC_IN_YUV420_3P; + cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P); break; case DRM_FORMAT_NV12: + cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P); + break; case DRM_FORMAT_NV16: - cfg |= (GSC_IN_CHROMA_ORDER_CBCR | - GSC_IN_YUV420_2P); + cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV422_2P); break; case DRM_FORMAT_NV12MT: cfg |= (GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE); @@ -796,18 +800,25 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt) GSC_OUT_CHROMA_ORDER_CRCB); break; case DRM_FORMAT_NV21: - case DRM_FORMAT_NV61: cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_2P); break; + case DRM_FORMAT_NV61: + cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV422_2P); + break; case DRM_FORMAT_YUV422: + cfg |= GSC_OUT_YUV422_3P; + break; case DRM_FORMAT_YUV420: + cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P); + break; case DRM_FORMAT_YVU420: - cfg |= GSC_OUT_YUV420_3P; + cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P); break; case DRM_FORMAT_NV12: + cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P); + break; case DRM_FORMAT_NV16: - cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | - GSC_OUT_YUV420_2P); + cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV422_2P); break; case DRM_FORMAT_NV12MT: cfg |= (GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE); diff --git a/drivers/gpu/drm/exynos/regs-gsc.h b/drivers/gpu/drm/exynos/regs-gsc.h index 9ad592707aaf..ade10966d6af 100644 --- a/drivers/gpu/drm/exynos/regs-gsc.h +++ b/drivers/gpu/drm/exynos/regs-gsc.h @@ -138,6 +138,7 @@ #define GSC_OUT_YUV420_3P (3 << 4) #define GSC_OUT_YUV422_1P (4 << 4) #define GSC_OUT_YUV422_2P (5 << 4) +#define GSC_OUT_YUV422_3P (6 << 4) #define GSC_OUT_YUV444 (7 << 4) #define GSC_OUT_TILE_TYPE_MASK (1 << 2) #define GSC_OUT_TILE_C_16x8 (0 << 2) From 7af7d6ec76a6d71c399057c94dc23a5bfb7cbf2b Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Thu, 28 Jun 2018 04:52:15 -0700 Subject: [PATCH 282/392] bnx2x: Fix receiving tx-timeout in error or recovery state. [ Upstream commit 484c016d9392786ce5c74017c206c706f29f823d ] Driver performs the internal reload when it receives tx-timeout event from the OS. Internal reload might fail in some scenarios e.g., fatal HW issues. In such cases OS still see the link, which would result in undesirable functionalities such as re-generation of tx-timeouts. The patch addresses this issue by indicating the link-down to OS when tx-timeout is detected, and keeping the link in down state till the internal reload is successful. Please consider applying it to 'net' branch. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Ariel Elior Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 1 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 6 ++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 2559206d8704..2ce16ce5b796 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1613,6 +1613,7 @@ struct bnx2x { struct link_vars link_vars; u32 link_cnt; struct bnx2x_link_report_data last_reported_link; + bool force_link_down; struct mdio_if_info mdio; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index f41f53fe1340..82e6c7f12ec2 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1257,6 +1257,11 @@ void __bnx2x_link_report(struct bnx2x *bp) { struct bnx2x_link_report_data cur_data; + if (bp->force_link_down) { + bp->link_vars.link_up = 0; + return; + } + /* reread mf_cfg */ if (IS_PF(bp) && !CHIP_IS_E1(bp)) bnx2x_read_mf_cfg(bp); @@ -2799,6 +2804,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) bp->pending_max = 0; } + bp->force_link_down = false; if (bp->port.pmf) { rc = bnx2x_initial_phy_init(bp, load_mode); if (rc) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index f8e8206d7620..8063e928827c 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -10036,6 +10036,12 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work) bp->sp_rtnl_state = 0; smp_mb(); + /* Immediately indicate link as down */ + bp->link_vars.link_up = 0; + bp->force_link_down = true; + netif_carrier_off(bp->dev); + BNX2X_ERR("Indicating link is down due to Tx-timeout\n"); + bnx2x_nic_unload(bp, UNLOAD_NORMAL, true); bnx2x_nic_load(bp, LOAD_NORMAL); From d35f87465a55d3d4d06fa2cddd2a349176a6019f Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Mon, 18 Jun 2018 15:34:14 +1000 Subject: [PATCH 283/392] m68k: fix "bad page state" oops on ColdFire boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit ecd60532e060e45c63c57ecf1c8549b1d656d34d ] Booting a ColdFire m68k core with MMU enabled causes a "bad page state" oops since commit 1d40a5ea01d5 ("mm: mark pages in use for page tables"): BUG: Bad page state in process sh pfn:01ce2 page:004fefc8 count:0 mapcount:-1024 mapping:00000000 index:0x0 flags: 0x0() raw: 00000000 00000000 00000000 fffffbff 00000000 00000100 00000200 00000000 raw: 039c4000 page dumped because: nonzero mapcount Modules linked in: CPU: 0 PID: 22 Comm: sh Not tainted 4.17.0-07461-g1d40a5ea01d5 #13 Fix by calling pgtable_page_dtor() in our __pte_free_tlb() code path, so that the PG_table flag is cleared before we free the pte page. Note that I had to change the type of pte_free() to be static from extern. Otherwise you get a lot of warnings like this: ./arch/m68k/include/asm/mcf_pgalloc.h:80:2: warning: ‘pgtable_page_dtor’ is static but used in inline function ‘pte_free’ which is not static pgtable_page_dtor(page); ^ And making it static is consistent with our use of this in the other m68k pgalloc definitions of pte_free(). Signed-off-by: Greg Ungerer CC: Matthew Wilcox Reviewed-by: Geert Uytterhoeven Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/m68k/include/asm/mcf_pgalloc.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/m68k/include/asm/mcf_pgalloc.h b/arch/m68k/include/asm/mcf_pgalloc.h index f9924fbcfe42..456e3f75ef3b 100644 --- a/arch/m68k/include/asm/mcf_pgalloc.h +++ b/arch/m68k/include/asm/mcf_pgalloc.h @@ -43,6 +43,7 @@ extern inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address) static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page, unsigned long address) { + pgtable_page_dtor(page); __free_page(page); } @@ -73,8 +74,9 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm, return page; } -extern inline void pte_free(struct mm_struct *mm, struct page *page) +static inline void pte_free(struct mm_struct *mm, struct page *page) { + pgtable_page_dtor(page); __free_page(page); } From d9823784f9abc69f0ae1b80c377b896e5ccb2989 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 26 Jun 2018 08:37:09 -0300 Subject: [PATCH 284/392] ARM: imx_v4_v5_defconfig: Select ULPI support [ Upstream commit 2ceb2780b790b74bc408a949f6aedbad8afa693e ] Select CONFIG_USB_CHIPIDEA_ULPI and CONFIG_USB_ULPI_BUS so that USB ULPI can be functional on some boards like that use ULPI interface. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/configs/imx_v4_v5_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig index e6b0007355f8..0dfa0029470f 100644 --- a/arch/arm/configs/imx_v4_v5_defconfig +++ b/arch/arm/configs/imx_v4_v5_defconfig @@ -146,9 +146,11 @@ CONFIG_USB_STORAGE=y CONFIG_USB_CHIPIDEA=y CONFIG_USB_CHIPIDEA_UDC=y CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_CHIPIDEA_ULPI=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_GADGET=y CONFIG_USB_ETH=m +CONFIG_USB_ULPI_BUS=y CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y From 766c02b662c9c90d4d89ace26c996586fd3b15c3 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Thu, 8 Mar 2018 21:58:43 +0100 Subject: [PATCH 285/392] tracing: Use __printf markup to silence compiler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 26b68dd2f48fe7699a89f0cfbb9f4a650dc1c837 ] Silence warnings (triggered at W=1) by adding relevant __printf attributes. CC kernel/trace/trace.o kernel/trace/trace.c: In function ‘__trace_array_vprintk’: kernel/trace/trace.c:2979:2: warning: function might be possible candidate for ‘gnu_printf’ format attribute [-Wsuggest-attribute=format] len = vscnprintf(tbuffer, TRACE_BUF_SIZE, fmt, args); ^~~ AR kernel/trace/built-in.o Link: http://lkml.kernel.org/r/20180308205843.27447-1-malat@debian.org Signed-off-by: Mathieu Malaterre Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index f5f18f398ce9..521da2cfeb4f 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -2137,6 +2137,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) } EXPORT_SYMBOL_GPL(trace_vbprintk); +__printf(3, 0) static int __trace_array_vprintk(struct ring_buffer *buffer, unsigned long ip, const char *fmt, va_list args) @@ -2190,12 +2191,14 @@ __trace_array_vprintk(struct ring_buffer *buffer, return len; } +__printf(3, 0) int trace_array_vprintk(struct trace_array *tr, unsigned long ip, const char *fmt, va_list args) { return __trace_array_vprintk(tr->trace_buffer.buffer, ip, fmt, args); } +__printf(3, 0) int trace_array_printk(struct trace_array *tr, unsigned long ip, const char *fmt, ...) { @@ -2211,6 +2214,7 @@ int trace_array_printk(struct trace_array *tr, return ret; } +__printf(3, 4) int trace_array_printk_buf(struct ring_buffer *buffer, unsigned long ip, const char *fmt, ...) { @@ -2226,6 +2230,7 @@ int trace_array_printk_buf(struct ring_buffer *buffer, return ret; } +__printf(2, 0) int trace_vprintk(unsigned long ip, const char *fmt, va_list args) { return trace_array_vprintk(&global_trace, ip, fmt, args); From 46ed892ba240b6ee058b72b90bab9d8bc689d889 Mon Sep 17 00:00:00 2001 From: Yuiko Oshino Date: Tue, 3 Jul 2018 11:21:46 -0400 Subject: [PATCH 286/392] smsc75xx: Add workaround for gigabit link up hardware errata. [ Upstream commit d461e3da905332189aad546b2ad9adbe6071c7cc ] In certain conditions, the device may not be able to link in gigabit mode. This software workaround ensures that the device will not enter the failure state. Fixes: d0cad871703b898a442e4049c532ec39168e5b57 ("SMSC75XX USB 2.0 Gigabit Ethernet Devices") Signed-off-by: Yuiko Oshino Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/smsc75xx.c | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index b0fce2a6fe57..3850c342bc54 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -81,6 +81,9 @@ static bool turbo_mode = true; module_param(turbo_mode, bool, 0644); MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); +static int smsc75xx_link_ok_nopm(struct usbnet *dev); +static int smsc75xx_phy_gig_workaround(struct usbnet *dev); + static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index, u32 *data, int in_pm) { @@ -840,6 +843,9 @@ static int smsc75xx_phy_initialize(struct usbnet *dev) return -EIO; } + /* phy workaround for gig link */ + smsc75xx_phy_gig_workaround(dev); + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); @@ -978,6 +984,62 @@ static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm) return -EIO; } +static int smsc75xx_phy_gig_workaround(struct usbnet *dev) +{ + struct mii_if_info *mii = &dev->mii; + int ret = 0, timeout = 0; + u32 buf, link_up = 0; + + /* Set the phy in Gig loopback */ + smsc75xx_mdio_write(dev->net, mii->phy_id, MII_BMCR, 0x4040); + + /* Wait for the link up */ + do { + link_up = smsc75xx_link_ok_nopm(dev); + usleep_range(10000, 20000); + timeout++; + } while ((!link_up) && (timeout < 1000)); + + if (timeout >= 1000) { + netdev_warn(dev->net, "Timeout waiting for PHY link up\n"); + return -EIO; + } + + /* phy reset */ + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); + if (ret < 0) { + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret); + return ret; + } + + buf |= PMT_CTL_PHY_RST; + + ret = smsc75xx_write_reg(dev, PMT_CTL, buf); + if (ret < 0) { + netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret); + return ret; + } + + timeout = 0; + do { + usleep_range(10000, 20000); + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); + if (ret < 0) { + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", + ret); + return ret; + } + timeout++; + } while ((buf & PMT_CTL_PHY_RST) && (timeout < 100)); + + if (timeout >= 100) { + netdev_warn(dev->net, "timeout waiting for PHY Reset\n"); + return -EIO; + } + + return 0; +} + static int smsc75xx_reset(struct usbnet *dev) { struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); From 2e792ad70b398404cba6385c50d8452a37126008 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 4 Jul 2018 20:25:32 +0200 Subject: [PATCH 287/392] netfilter: x_tables: set module owner for icmp(6) matches [ Upstream commit d376bef9c29b3c65aeee4e785fffcd97ef0a9a81 ] nft_compat relies on xt_request_find_match to increment refcount of the module that provides the match/target. The (builtin) icmp matches did't set the module owner so it was possible to rmmod ip(6)tables while icmp extensions were still in use. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv4/netfilter/ip_tables.c | 1 + net/ipv6/netfilter/ip6_tables.c | 1 + 2 files changed, 2 insertions(+) diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 60ba5b0f6474..8d633b6993bb 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -2069,6 +2069,7 @@ static struct xt_match ipt_builtin_mt[] __read_mostly = { .checkentry = icmp_checkentry, .proto = IPPROTO_ICMP, .family = NFPROTO_IPV4, + .me = THIS_MODULE, }, }; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index b4bfd07dc8eb..02f50cfc5592 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -2071,6 +2071,7 @@ static struct xt_match ip6t_builtin_mt[] __read_mostly = { .checkentry = icmp6_checkentry, .proto = IPPROTO_ICMPV6, .family = NFPROTO_IPV6, + .me = THIS_MODULE, }, }; From f8ebc472bb246313cf5d5ac8a1733bc1e7a3d453 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 6 Jul 2018 22:15:00 +0200 Subject: [PATCH 288/392] ARM: pxa: irq: fix handling of ICMR registers in suspend/resume [ Upstream commit 0c1049dcb4ceec640d8bd797335bcbebdcab44d2 ] PXA3xx platforms have 56 interrupts that are stored in two ICMR registers. The code in pxa_irq_suspend() and pxa_irq_resume() however does a simple division by 32 which only leads to one register being saved at suspend and restored at resume time. The NAND interrupt setting, for instance, is lost. Fix this by using DIV_ROUND_UP() instead. Signed-off-by: Daniel Mack Signed-off-by: Robert Jarzmik Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-pxa/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 0eecd83c624e..d7f382856c42 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -160,7 +160,7 @@ static int pxa_irq_suspend(void) { int i; - for (i = 0; i < pxa_internal_irq_nr / 32; i++) { + for (i = 0; i < DIV_ROUND_UP(pxa_internal_irq_nr, 32); i++) { void __iomem *base = irq_base(i); saved_icmr[i] = __raw_readl(base + ICMR); @@ -179,7 +179,7 @@ static void pxa_irq_resume(void) { int i; - for (i = 0; i < pxa_internal_irq_nr / 32; i++) { + for (i = 0; i < DIV_ROUND_UP(pxa_internal_irq_nr, 32); i++) { void __iomem *base = irq_base(i); __raw_writel(saved_icmr[i], base + ICMR); From 7fed6b5ed532e0c056e9846248cc4bdbc269fada Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 24 Jun 2018 14:35:10 +0100 Subject: [PATCH 289/392] drm/armada: fix colorkey mode property [ Upstream commit d378859a667edc99e3473704847698cae97ca2b1 ] The colorkey mode property was not correctly disabling the colorkeying when "disabled" mode was selected. Arrange for this to work as one would expect. Signed-off-by: Russell King Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/armada/armada_hw.h | 1 + drivers/gpu/drm/armada/armada_overlay.c | 30 ++++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h index 27319a8335e2..345dc4d0851e 100644 --- a/drivers/gpu/drm/armada/armada_hw.h +++ b/drivers/gpu/drm/armada/armada_hw.h @@ -160,6 +160,7 @@ enum { CFG_ALPHAM_GRA = 0x1 << 16, CFG_ALPHAM_CFG = 0x2 << 16, CFG_ALPHA_MASK = 0xff << 8, +#define CFG_ALPHA(x) ((x) << 8) CFG_PIXCMD_MASK = 0xff, }; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index c5b06fdb459c..f8c3b7d3597c 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -26,6 +26,7 @@ struct armada_plane_properties { uint16_t contrast; uint16_t saturation; uint32_t colorkey_mode; + uint32_t colorkey_enable; }; struct armada_plane { @@ -62,11 +63,13 @@ armada_ovl_update_attr(struct armada_plane_properties *prop, writel_relaxed(0x00002000, dcrtc->base + LCD_SPU_CBSH_HUE); spin_lock_irq(&dcrtc->irq_lock); - armada_updatel(prop->colorkey_mode | CFG_ALPHAM_GRA, - CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK, - dcrtc->base + LCD_SPU_DMA_CTRL1); - - armada_updatel(ADV_GRACOLORKEY, 0, dcrtc->base + LCD_SPU_ADV_REG); + armada_updatel(prop->colorkey_mode, + CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK, + dcrtc->base + LCD_SPU_DMA_CTRL1); + if (dcrtc->variant->has_spu_adv_reg) + armada_updatel(prop->colorkey_enable, + ADV_GRACOLORKEY | ADV_VIDCOLORKEY, + dcrtc->base + LCD_SPU_ADV_REG); spin_unlock_irq(&dcrtc->irq_lock); } @@ -329,8 +332,17 @@ static int armada_plane_set_property(struct drm_plane *plane, dplane->prop.colorkey_vb |= K2B(val); update_attr = true; } else if (property == priv->colorkey_mode_prop) { - dplane->prop.colorkey_mode &= ~CFG_CKMODE_MASK; - dplane->prop.colorkey_mode |= CFG_CKMODE(val); + if (val == CKMODE_DISABLE) { + dplane->prop.colorkey_mode = + CFG_CKMODE(CKMODE_DISABLE) | + CFG_ALPHAM_CFG | CFG_ALPHA(255); + dplane->prop.colorkey_enable = 0; + } else { + dplane->prop.colorkey_mode = + CFG_CKMODE(val) | + CFG_ALPHAM_GRA | CFG_ALPHA(0); + dplane->prop.colorkey_enable = ADV_GRACOLORKEY; + } update_attr = true; } else if (property == priv->brightness_prop) { dplane->prop.brightness = val - 256; @@ -449,7 +461,9 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) dplane->prop.colorkey_yr = 0xfefefe00; dplane->prop.colorkey_ug = 0x01010100; dplane->prop.colorkey_vb = 0x01010100; - dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB); + dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB) | + CFG_ALPHAM_GRA | CFG_ALPHA(0); + dplane->prop.colorkey_enable = ADV_GRACOLORKEY; dplane->prop.brightness = 0; dplane->prop.contrast = 0x4000; dplane->prop.saturation = 0x4000; From c76800bd4fe86df8b26fa99871114ea8d83fe2ab Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Wed, 11 Jul 2018 12:54:54 -0500 Subject: [PATCH 290/392] ARM: dts: am3517.dtsi: Disable reference to OMAP3 OTG controller [ Upstream commit 923847413f7316b5ced3491769b3fefa6c56a79a ] The AM3517 has a different OTG controller location than the OMAP3, which is included from omap3.dtsi. This results in a hwmod error. Since the AM3517 has a different OTG controller address, this patch disabes one that is isn't available. Signed-off-by: Adam Ford Signed-off-by: Tony Lindgren Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/am3517.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi index 5a452fdd7c5d..1f4b2033ba2b 100644 --- a/arch/arm/boot/dts/am3517.dtsi +++ b/arch/arm/boot/dts/am3517.dtsi @@ -62,6 +62,11 @@ }; }; +/* Table Table 5-79 of the TRM shows 480ab000 is reserved */ +&usb_otg_hs { + status = "disabled"; +}; + &iva { status = "disabled"; }; From 89a9bc2dfec3e85c2809a11bc24166d3eb534f0b Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 18 Jun 2018 12:02:00 -0400 Subject: [PATCH 291/392] ixgbe: Be more careful when modifying MAC filters [ Upstream commit d14c780c11fbc10f66c43e7b64eefe87ca442bd3 ] This change makes it so that we are much more explicit about the ordering of updates to the receive address register (RAR) table. Prior to this patch I believe we may have been updating the table while entries were still active, or possibly allowing for reordering of things since we weren't explicitly flushing writes to either the lower or upper portion of the register prior to accessing the other half. Signed-off-by: Alexander Duyck Reviewed-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index b5f484bf3fda..4be0a22757d2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -1781,7 +1781,12 @@ s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, if (enable_addr != 0) rar_high |= IXGBE_RAH_AV; + /* Record lower 32 bits of MAC address and then make + * sure that write is flushed to hardware before writing + * the upper 16 bits and setting the valid bit. + */ IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low); + IXGBE_WRITE_FLUSH(hw); IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); return 0; @@ -1813,8 +1818,13 @@ s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index) rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV); - IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0); + /* Clear the address valid bit and upper 16 bits of the address + * before clearing the lower bits. This way we aren't updating + * a live filter. + */ IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); + IXGBE_WRITE_FLUSH(hw); + IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0); /* clear VMDq pool/queue selection for this RAR */ hw->mac.ops.clear_vmdq(hw, index, IXGBE_CLEAR_VMDQ_ALL); From 9012fe049dad669ab55febd1bc1c6ba751c50967 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 12 Jul 2018 15:23:45 +0300 Subject: [PATCH 292/392] qlogic: check kstrtoul() for errors [ Upstream commit 5fc853cc01c68f84984ecc2d5fd777ecad78240f ] We accidentally left out the error handling for kstrtoul(). Fixes: a520030e326a ("qlcnic: Implement flash sysfs callback for 83xx adapter") Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index 59a721fba018..8c787fab7993 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -1136,6 +1136,8 @@ static ssize_t qlcnic_83xx_sysfs_flash_write_handler(struct file *filp, return QL_STATUS_INVALID_PARAM; ret = kstrtoul(buf, 16, &data); + if (ret) + return ret; switch (data) { case QLC_83XX_FLASH_SECTOR_ERASE_CMD: From 01c755b1b97525ed17a7e6a33d9ef97be86c47fe Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 16 Jul 2018 17:58:10 -0500 Subject: [PATCH 293/392] net: usb: rtl8150: demote allmulti message to dev_dbg() [ Upstream commit 3a9b0455062ffb9d2f6cd4473a76e3456f318c9f ] This driver can spam the kernel log with multiple messages of: net eth0: eth0: allmulti set Usually 4 or 8 at a time (probably because of using ConnMan). This message doesn't seem useful, so let's demote it from dev_info() to dev_dbg(). Signed-off-by: David Lechner Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/rtl8150.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index eab8fba1f8c9..d19f7c23c2c1 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -681,7 +681,7 @@ static void rtl8150_set_multicast(struct net_device *netdev) (netdev->flags & IFF_ALLMULTI)) { rx_creg &= 0xfffe; rx_creg |= 0x0002; - dev_info(&netdev->dev, "%s: allmulti set\n", netdev->name); + dev_dbg(&netdev->dev, "%s: allmulti set\n", netdev->name); } else { /* ~RX_MULTICAST, ~RX_PROMISCUOUS */ rx_creg &= 0x00fc; From 1357eabe9f55df5df2dce2cb14e19f851ec86030 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Wed, 18 Jul 2018 08:31:43 +0200 Subject: [PATCH 294/392] net: qca_spi: Avoid packet drop during initial sync [ Upstream commit b2bab426dc715de147f8039a3fccff27d795f4eb ] As long as the synchronization with the QCA7000 isn't finished, we cannot accept packets from the upper layers. So let the SPI thread enable the TX queue after sync and avoid unwanted packet drop. Signed-off-by: Stefan Wahren Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000") Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qualcomm/qca_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 487d6ab771e9..008ba3054d69 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -636,7 +636,7 @@ qcaspi_netdev_open(struct net_device *dev) return ret; } - netif_start_queue(qca->net_dev); + /* SPI thread takes care of TX queue */ return 0; } From 45d5a5d0d64a1c03db175addbcf3c529d78d783a Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Wed, 18 Jul 2018 08:31:44 +0200 Subject: [PATCH 295/392] net: qca_spi: Make sure the QCA7000 reset is triggered [ Upstream commit 711c62dfa6bdb4326ca6c587f295ea5c4f7269de ] In case the SPI thread is not running, a simple reset of sync state won't fix the transmit timeout. We also need to wake up the kernel thread. Signed-off-by: Stefan Wahren Fixes: ed7d42e24eff ("net: qca_spi: fix transmit queue timeout handling") Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qualcomm/qca_spi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 008ba3054d69..2ec7fa82b4cf 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -740,6 +740,9 @@ qcaspi_netdev_tx_timeout(struct net_device *dev) qca->net_dev->stats.tx_errors++; /* Trigger tx queue flush and QCA7000 reset */ qca->sync = QCASPI_SYNC_UNKNOWN; + + if (qca->spi_thread) + wake_up_process(qca->spi_thread); } static int From dfd3805948b6e0165ad2c836ba5ecab2328ea620 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 17 Jul 2018 18:27:45 -0700 Subject: [PATCH 296/392] tcp: identify cryptic messages as TCP seq # bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e56b8ce363a36fb7b74b80aaa5cc9084f2c908b4 ] Attempt to make cryptic TCP seq number error messages clearer by (1) identifying the source of the message as "TCP", (2) identifying the errors as "seq # bug", and (3) grouping the field identifiers and values by separating them with commas. E.g., the following message is changed from: recvmsg bug 2: copied 73BCB6CD seq 70F17CBE rcvnxt 73BCB9AA fl 0 WARNING: CPU: 2 PID: 1501 at /linux/net/ipv4/tcp.c:1881 tcp_recvmsg+0x649/0xb90 to: TCP recvmsg seq # bug 2: copied 73BCB6CD, seq 70F17CBE, rcvnxt 73BCB9AA, fl 0 WARNING: CPU: 2 PID: 1501 at /linux/net/ipv4/tcp.c:2011 tcp_recvmsg+0x694/0xba0 Suggested-by: 積丹尼 Dan Jacobson Signed-off-by: Randy Dunlap Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index a542c86e370f..e2a545f3db68 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1668,7 +1668,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, * shouldn't happen. */ if (WARN(before(*seq, TCP_SKB_CB(skb)->seq), - "recvmsg bug: copied %X seq %X rcvnxt %X fl %X\n", + "TCP recvmsg seq # bug: copied %X, seq %X, rcvnxt %X, fl %X\n", *seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt, flags)) break; @@ -1681,7 +1681,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) goto found_fin_ok; WARN(!(flags & MSG_PEEK), - "recvmsg bug 2: copied %X seq %X rcvnxt %X fl %X\n", + "TCP recvmsg seq # bug 2: copied %X, seq %X, rcvnxt %X, fl %X\n", *seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt, flags); } From 5554e8fc645c4e20d9356135d35b185a62a99eb2 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 21 Aug 2018 13:31:50 -0700 Subject: [PATCH 297/392] staging: android: ion: check for kref overflow This patch is against 4.4. It does not apply to master due to a large rework of ion in 4.12 which removed the affected functions altogther. 4c23cbff073f3b9b ("staging: android: ion: Remove import interface") Userspace can cause the kref to handles to increment arbitrarily high. Ensure it does not overflow. Signed-off-by: Daniel Rosenberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 8cc4cdb33400..bce7e8ea361a 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -15,6 +15,7 @@ * */ +#include #include #include #include @@ -389,6 +390,16 @@ static void ion_handle_get(struct ion_handle *handle) kref_get(&handle->ref); } +/* Must hold the client lock */ +static struct ion_handle *ion_handle_get_check_overflow( + struct ion_handle *handle) +{ + if (atomic_read(&handle->ref.refcount) + 1 == 0) + return ERR_PTR(-EOVERFLOW); + ion_handle_get(handle); + return handle; +} + static int ion_handle_put_nolock(struct ion_handle *handle) { int ret; @@ -435,9 +446,9 @@ static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, handle = idr_find(&client->idr, id); if (handle) - ion_handle_get(handle); + return ion_handle_get_check_overflow(handle); - return handle ? handle : ERR_PTR(-EINVAL); + return ERR_PTR(-EINVAL); } struct ion_handle *ion_handle_get_by_id(struct ion_client *client, @@ -1197,7 +1208,7 @@ struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd) /* if a handle exists for this buffer just take a reference to it */ handle = ion_handle_lookup(client, buffer); if (!IS_ERR(handle)) { - ion_handle_get(handle); + handle = ion_handle_get_check_overflow(handle); mutex_unlock(&client->lock); goto end; } From 966e597ed466a49c616d3647b144cbc6493bf7de Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 18 Jun 2018 21:35:07 -0700 Subject: [PATCH 298/392] xfrm_user: prevent leaking 2 bytes of kernel memory commit 45c180bc29babbedd6b8c01b975780ef44d9d09c upstream. struct xfrm_userpolicy_type has two holes, so we should not use C99 style initializer. KMSAN report: BUG: KMSAN: kernel-infoleak in copyout lib/iov_iter.c:140 [inline] BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x1b14/0x2800 lib/iov_iter.c:571 CPU: 1 PID: 4520 Comm: syz-executor841 Not tainted 4.17.0+ #5 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:113 kmsan_report+0x188/0x2a0 mm/kmsan/kmsan.c:1117 kmsan_internal_check_memory+0x138/0x1f0 mm/kmsan/kmsan.c:1211 kmsan_copy_to_user+0x7a/0x160 mm/kmsan/kmsan.c:1253 copyout lib/iov_iter.c:140 [inline] _copy_to_iter+0x1b14/0x2800 lib/iov_iter.c:571 copy_to_iter include/linux/uio.h:106 [inline] skb_copy_datagram_iter+0x422/0xfa0 net/core/datagram.c:431 skb_copy_datagram_msg include/linux/skbuff.h:3268 [inline] netlink_recvmsg+0x6f1/0x1900 net/netlink/af_netlink.c:1959 sock_recvmsg_nosec net/socket.c:802 [inline] sock_recvmsg+0x1d6/0x230 net/socket.c:809 ___sys_recvmsg+0x3fe/0x810 net/socket.c:2279 __sys_recvmmsg+0x58e/0xe30 net/socket.c:2391 do_sys_recvmmsg+0x2a6/0x3e0 net/socket.c:2472 __do_sys_recvmmsg net/socket.c:2485 [inline] __se_sys_recvmmsg net/socket.c:2481 [inline] __x64_sys_recvmmsg+0x15d/0x1c0 net/socket.c:2481 do_syscall_64+0x15b/0x230 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x446ce9 RSP: 002b:00007fc307918db8 EFLAGS: 00000293 ORIG_RAX: 000000000000012b RAX: ffffffffffffffda RBX: 00000000006dbc24 RCX: 0000000000446ce9 RDX: 000000000000000a RSI: 0000000020005040 RDI: 0000000000000003 RBP: 00000000006dbc20 R08: 0000000020004e40 R09: 0000000000000000 R10: 0000000040000000 R11: 0000000000000293 R12: 0000000000000000 R13: 00007ffc8d2df32f R14: 00007fc3079199c0 R15: 0000000000000001 Uninit was stored to memory at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:279 [inline] kmsan_save_stack mm/kmsan/kmsan.c:294 [inline] kmsan_internal_chain_origin+0x12b/0x210 mm/kmsan/kmsan.c:685 kmsan_memcpy_origins+0x11d/0x170 mm/kmsan/kmsan.c:527 __msan_memcpy+0x109/0x160 mm/kmsan/kmsan_instr.c:413 __nla_put lib/nlattr.c:569 [inline] nla_put+0x276/0x340 lib/nlattr.c:627 copy_to_user_policy_type net/xfrm/xfrm_user.c:1678 [inline] dump_one_policy+0xbe1/0x1090 net/xfrm/xfrm_user.c:1708 xfrm_policy_walk+0x45a/0xd00 net/xfrm/xfrm_policy.c:1013 xfrm_dump_policy+0x1c0/0x2a0 net/xfrm/xfrm_user.c:1749 netlink_dump+0x9b5/0x1550 net/netlink/af_netlink.c:2226 __netlink_dump_start+0x1131/0x1270 net/netlink/af_netlink.c:2323 netlink_dump_start include/linux/netlink.h:214 [inline] xfrm_user_rcv_msg+0x8a3/0x9b0 net/xfrm/xfrm_user.c:2577 netlink_rcv_skb+0x37e/0x600 net/netlink/af_netlink.c:2448 xfrm_netlink_rcv+0xb2/0xf0 net/xfrm/xfrm_user.c:2598 netlink_unicast_kernel net/netlink/af_netlink.c:1310 [inline] netlink_unicast+0x1680/0x1750 net/netlink/af_netlink.c:1336 netlink_sendmsg+0x104f/0x1350 net/netlink/af_netlink.c:1901 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg net/socket.c:639 [inline] ___sys_sendmsg+0xec8/0x1320 net/socket.c:2117 __sys_sendmsg net/socket.c:2155 [inline] __do_sys_sendmsg net/socket.c:2164 [inline] __se_sys_sendmsg net/socket.c:2162 [inline] __x64_sys_sendmsg+0x331/0x460 net/socket.c:2162 do_syscall_64+0x15b/0x230 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Local variable description: ----upt.i@dump_one_policy Variable was created at: dump_one_policy+0x78/0x1090 net/xfrm/xfrm_user.c:1689 xfrm_policy_walk+0x45a/0xd00 net/xfrm/xfrm_policy.c:1013 Byte 130 of 137 is uninitialized Memory access starts at ffff88019550407f Fixes: c0144beaeca42 ("[XFRM] netlink: Use nla_put()/NLA_PUT() variantes") Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: Steffen Klassert Cc: Herbert Xu Signed-off-by: Steffen Klassert Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_user.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 0608819ba2b6..b1cd9f955182 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1597,9 +1597,11 @@ static inline size_t userpolicy_type_attrsize(void) #ifdef CONFIG_XFRM_SUB_POLICY static int copy_to_user_policy_type(u8 type, struct sk_buff *skb) { - struct xfrm_userpolicy_type upt = { - .type = type, - }; + struct xfrm_userpolicy_type upt; + + /* Sadly there are two holes in struct xfrm_userpolicy_type */ + memset(&upt, 0, sizeof(upt)); + upt.type = type; return nla_put(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); } From c022960cd731d3aa9df43a478cabae0b4c1f5bf4 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 17 Jul 2018 21:03:15 +0200 Subject: [PATCH 299/392] netfilter: conntrack: dccp: treat SYNC/SYNCACK as invalid if no prior state commit 6613b6173dee098997229caf1f3b961c49da75e6 upstream. When first DCCP packet is SYNC or SYNCACK, we insert a new conntrack that has an un-initialized timeout value, i.e. such entry could be reaped at any time. Mark them as INVALID and only ignore SYNC/SYNCACK when connection had an old state. Reported-by: syzbot+6f18401420df260e37ed@syzkaller.appspotmail.com Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_conntrack_proto_dccp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index cb372f96f10d..a46e6915a9ce 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -244,14 +244,14 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = * We currently ignore Sync packets * * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ - sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, }, [DCCP_PKT_SYNCACK] = { /* * We currently ignore SyncAck packets * * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ - sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, }, }, [CT_DCCP_ROLE_SERVER] = { @@ -372,14 +372,14 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = * We currently ignore Sync packets * * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ - sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, }, [DCCP_PKT_SYNCACK] = { /* * We currently ignore SyncAck packets * * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ - sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, }, }, }; From c1d01e128c81ee0a5616e8445ae937652ada0392 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 6 Aug 2018 10:38:34 -0400 Subject: [PATCH 300/392] packet: refine ring v3 block size test to hold one frame commit 4576cd469d980317c4edd9173f8b694aa71ea3a3 upstream. TPACKET_V3 stores variable length frames in fixed length blocks. Blocks must be able to store a block header, optional private space and at least one minimum sized frame. Frames, even for a zero snaplen packet, store metadata headers and optional reserved space. In the block size bounds check, ensure that the frame of the chosen configuration fits. This includes sockaddr_ll and optional tp_reserve. Syzbot was able to construct a ring with insuffient room for the sockaddr_ll in the header of a zero-length frame, triggering an out-of-bounds write in dev_parse_header. Convert the comparison to less than, as zero is a valid snap len. This matches the test for minimum tp_frame_size immediately below. Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.") Fixes: eb73190f4fbe ("net/packet: refine check for priv area size") Reported-by: syzbot Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index b7df7601eb86..473858cb4c5d 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3853,6 +3853,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, } if (req->tp_block_nr) { + unsigned int min_frame_size; + /* Sanity tests and some calculations */ err = -EBUSY; if (unlikely(rb->pg_vec)) @@ -3875,12 +3877,12 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, goto out; if (unlikely(req->tp_block_size & (PAGE_SIZE - 1))) goto out; + min_frame_size = po->tp_hdrlen + po->tp_reserve; if (po->tp_version >= TPACKET_V3 && - req->tp_block_size <= - BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv) + sizeof(struct tpacket3_hdr)) + req->tp_block_size < + BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv) + min_frame_size) goto out; - if (unlikely(req->tp_frame_size < po->tp_hdrlen + - po->tp_reserve)) + if (unlikely(req->tp_frame_size < min_frame_size)) goto out; if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1))) goto out; From 3311a3935f86e0b28cf0884b18cd26d5b6d88bc3 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Thu, 19 Jul 2018 17:27:31 -0500 Subject: [PATCH 301/392] PCI: hotplug: Don't leak pci_slot on registration failure commit 4ce6435820d1f1cc2c2788e232735eb244bcc8a3 upstream. If addition of sysfs files fails on registration of a hotplug slot, the struct pci_slot as well as the entry in the slot_list is leaked. The issue has been present since the hotplug core was introduced in 2002: https://git.kernel.org/tglx/history/c/a8a2069f432c Perhaps the idea was that even though sysfs addition fails, the slot should still be usable. But that's not how drivers use the interface, they abort probe if a non-zero value is returned. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org # v2.4.15+ Cc: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pci_hotplug_core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 56d8486dc167..cdc109ec5b82 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -457,8 +457,17 @@ int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, list_add(&slot->slot_list, &pci_hotplug_slot_list); result = fs_add_slot(pci_slot); + if (result) + goto err_list_del; + kobject_uevent(&pci_slot->kobj, KOBJ_ADD); dbg("Added slot %s to the list\n", name); + goto out; + +err_list_del: + list_del(&slot->slot_list); + pci_slot->hotplug = NULL; + pci_destroy_slot(pci_slot); out: mutex_unlock(&pci_hp_mutex); return result; From 88f8dcdb69e35da54b5b7579403d365df457f093 Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Tue, 21 Aug 2018 21:59:37 -0700 Subject: [PATCH 302/392] reiserfs: fix broken xattr handling (heap corruption, bad retval) commit a13f085d111e90469faf2d9965eb39b11c114d7e upstream. This fixes the following issues: - When a buffer size is supplied to reiserfs_listxattr() such that each individual name fits, but the concatenation of all names doesn't fit, reiserfs_listxattr() overflows the supplied buffer. This leads to a kernel heap overflow (verified using KASAN) followed by an out-of-bounds usercopy and is therefore a security bug. - When a buffer size is supplied to reiserfs_listxattr() such that a name doesn't fit, -ERANGE should be returned. But reiserfs instead just truncates the list of names; I have verified that if the only xattr on a file has a longer name than the supplied buffer length, listxattr() incorrectly returns zero. With my patch applied, -ERANGE is returned in both cases and the memory corruption doesn't happen anymore. Credit for making me clean this code up a bit goes to Al Viro, who pointed out that the ->actor calling convention is suboptimal and should be changed. Link: http://lkml.kernel.org/r/20180802151539.5373-1-jannh@google.com Fixes: 48b32a3553a5 ("reiserfs: use generic xattr handlers") Signed-off-by: Jann Horn Acked-by: Jeff Mahoney Cc: Eric Biggers Cc: Al Viro Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/xattr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 7c36898af402..59b29acb6419 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -842,8 +842,10 @@ static int listxattr_filler(void *buf, const char *name, int namelen, size = handler->list(b->dentry, b->buf + b->pos, b->size, name, namelen, handler->flags); - if (size > b->size) + if (b->pos + size > b->size) { + b->pos = -ERANGE; return -ERANGE; + } } else { size = handler->list(b->dentry, NULL, 0, name, namelen, handler->flags); From a5f9be3576c3f9dd871f68eaf482278c0b3a6df2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 28 Aug 2018 07:21:37 +0200 Subject: [PATCH 303/392] Linux 3.18.120 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6f85cc732008..2ba32f17a470 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 18 -SUBLEVEL = 119 +SUBLEVEL = 120 EXTRAVERSION = NAME = Diseased Newt From 319bc6ceb7c14d1d0350a8307f8a59a3fba161ae Mon Sep 17 00:00:00 2001 From: Ethan Zhao Date: Mon, 4 Sep 2017 13:59:34 +0800 Subject: [PATCH 304/392] sched/sysctl: Check user input value of sysctl_sched_time_avg commit 5ccba44ba118a5000cccc50076b0344632459779 upstream. System will hang if user set sysctl_sched_time_avg to 0: [root@XXX ~]# sysctl kernel.sched_time_avg_ms=0 Stack traceback for pid 0 0xffff883f6406c600 0 0 1 3 R 0xffff883f6406cf50 *swapper/3 ffff883f7ccc3ae8 0000000000000018 ffffffff810c4dd0 0000000000000000 0000000000017800 ffff883f7ccc3d78 0000000000000003 ffff883f7ccc3bf8 ffffffff810c4fc9 ffff883f7ccc3c08 00000000810c5043 ffff883f7ccc3c08 Call Trace: [] ? update_group_capacity+0x110/0x200 [] ? update_sd_lb_stats+0x109/0x600 [] ? find_busiest_group+0x47/0x530 [] ? load_balance+0x194/0x900 [] ? update_rq_clock.part.83+0x1a/0xe0 [] ? rebalance_domains+0x152/0x290 [] ? run_rebalance_domains+0xdc/0x1d0 [] ? __do_softirq+0xfb/0x320 [] ? irq_exit+0x125/0x130 [] ? scheduler_ipi+0x97/0x160 [] ? smp_reschedule_interrupt+0x29/0x30 [] ? reschedule_interrupt+0x6e/0x80 [] ? cpuidle_enter_state+0xcc/0x230 [] ? cpuidle_enter_state+0x9c/0x230 [] ? cpuidle_enter+0x17/0x20 [] ? cpu_startup_entry+0x38c/0x420 [] ? start_secondary+0x173/0x1e0 Because divide-by-zero error happens in function: update_group_capacity() update_cpu_capacity() scale_rt_capacity() { ... total = sched_avg_period() + delta; used = div_u64(avg, total); ... } To fix this issue, check user input value of sysctl_sched_time_avg, keep it unchanged when hitting invalid input, and set the minimum limit of sysctl_sched_time_avg to 1 ms. Reported-by: James Puthukattukaran Signed-off-by: Ethan Zhao Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: efault@gmx.de Cc: ethan.kernel@gmail.com Cc: keescook@chromium.org Cc: mcgrof@kernel.org Cc: Link: http://lkml.kernel.org/r/1504504774-18253-1-git-send-email-ethan.zhao@oracle.com Signed-off-by: Ingo Molnar Cc: Steve Muckle Signed-off-by: Greg Kroah-Hartman --- kernel/sysctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 4e7c3dea4b85..72ab71e569cf 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -341,7 +341,8 @@ static struct ctl_table kern_table[] = { .data = &sysctl_sched_time_avg, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, + .extra1 = &one, }, { .procname = "sched_shares_window_ns", From 9a21340d0866664fc30a449b6d9d56659075f9d9 Mon Sep 17 00:00:00 2001 From: "yujuan.qi" Date: Mon, 31 Jul 2017 11:23:01 +0800 Subject: [PATCH 305/392] Cipso: cipso_v4_optptr enter infinite loop commit 40413955ee265a5e42f710940ec78f5450d49149 upstream. in for(),if((optlen > 0) && (optptr[1] == 0)), enter infinite loop. Test: receive a packet which the ip length > 20 and the first byte of ip option is 0, produce this issue Signed-off-by: yujuan.qi Acked-by: Paul Moore Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/cipso_ipv4.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index e08003d026eb..a5e2646c859d 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1591,9 +1591,17 @@ unsigned char *cipso_v4_optptr(const struct sk_buff *skb) int taglen; for (optlen = iph->ihl*4 - sizeof(struct iphdr); optlen > 0; ) { - if (optptr[0] == IPOPT_CIPSO) + switch (optptr[0]) { + case IPOPT_CIPSO: return optptr; - taglen = optptr[1]; + case IPOPT_END: + return NULL; + case IPOPT_NOOP: + taglen = 1; + break; + default: + taglen = optptr[1]; + } optlen -= taglen; optptr += taglen; } From ea0926cca04231dfb2f4813dd7c25748d4a31577 Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Thu, 21 Jun 2018 09:30:47 +0300 Subject: [PATCH 306/392] xfrm: fix missing dst_release() after policy blocking lbcast and multicast [ Upstream commit 8cc88773855f988d6a3bbf102bbd9dd9c828eb81 ] Fix missing dst_release() when local broadcast or multicast traffic is xfrm policy blocked. For IPv4 this results to dst leak: ip_route_output_flow() allocates dst_entry via __ip_route_output_key() and passes it to xfrm_lookup_route(). xfrm_lookup returns ERR_PTR(-EPERM) that is propagated. The dst that was allocated is never released. IPv4 local broadcast testcase: ping -b 192.168.1.255 & sleep 1 ip xfrm policy add src 0.0.0.0/0 dst 192.168.1.255/32 dir out action block IPv4 multicast testcase: ping 224.0.0.1 & sleep 1 ip xfrm policy add src 0.0.0.0/0 dst 224.0.0.1/32 dir out action block For IPv6 the missing dst_release() causes trouble e.g. when used in netns: ip netns add TEST ip netns exec TEST ip link set lo up ip link add dummy0 type dummy ip link set dev dummy0 netns TEST ip netns exec TEST ip addr add fd00::1111 dev dummy0 ip netns exec TEST ip link set dummy0 up ip netns exec TEST ping -6 -c 5 ff02::1%dummy0 & sleep 1 ip netns exec TEST ip xfrm policy add src ::/0 dst ff02::1 dir out action block wait ip netns del TEST After netns deletion we see: [ 258.239097] unregister_netdevice: waiting for lo to become free. Usage count = 2 [ 268.279061] unregister_netdevice: waiting for lo to become free. Usage count = 2 [ 278.367018] unregister_netdevice: waiting for lo to become free. Usage count = 2 [ 288.375259] unregister_netdevice: waiting for lo to become free. Usage count = 2 Fixes: ac37e2515c1a ("xfrm: release dst_orig in case of error in xfrm_lookup()") Signed-off-by: Tommi Rantala Signed-off-by: Steffen Klassert Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_policy.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d81f27046582..2f5b3dd702dc 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2291,6 +2291,9 @@ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig, if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE) return make_blackhole(net, dst_orig->ops->family, dst_orig); + if (IS_ERR(dst)) + dst_release(dst_orig); + return dst; } EXPORT_SYMBOL(xfrm_lookup_route); From 0b389a690180b16ff614af6bb8f9f887868b02ad Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 25 Jun 2018 14:00:07 +0200 Subject: [PATCH 307/392] xfrm: free skb if nlsk pointer is NULL [ Upstream commit 86126b77dcd551ce223e7293bb55854e3df05646 ] nlmsg_multicast() always frees the skb, so in case we cannot call it we must do that ourselves. Fixes: 21ee543edc0dea ("xfrm: fix race between netns cleanup and state expire notification") Signed-off-by: Florian Westphal Signed-off-by: Steffen Klassert Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_user.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index b1cd9f955182..4fe43d80c153 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -955,10 +955,12 @@ static inline int xfrm_nlmsg_multicast(struct net *net, struct sk_buff *skb, { struct sock *nlsk = rcu_dereference(net->xfrm.nlsk); - if (nlsk) - return nlmsg_multicast(nlsk, skb, pid, group, GFP_ATOMIC); - else - return -1; + if (!nlsk) { + kfree_skb(skb); + return -EPIPE; + } + + return nlmsg_multicast(nlsk, skb, pid, group, GFP_ATOMIC); } static inline size_t xfrm_spdinfo_msgsize(void) From 491e335a5e38e3f18a54e25b43c49593af0915da Mon Sep 17 00:00:00 2001 From: "mpubbise@codeaurora.org" Date: Mon, 2 Jul 2018 15:40:14 +0530 Subject: [PATCH 308/392] mac80211: add stations tied to AP_VLANs during hw reconfig [ Upstream commit 19103a4bfb42f320395daa5616ece3e89e759d63 ] As part of hw reconfig, only stations linked to AP interfaces are added back to the driver ignoring those which are tied to AP_VLAN interfaces. It is true that there could be stations tied to the AP_VLAN interface while serving 4addr clients or when using AP_VLAN for VLAN operations; we should be adding these stations back to the driver as part of hw reconfig, failing to do so can cause functional issues. In the case of ath10k driver, the following errors were observed. ath10k_pci : failed to install key for non-existent peer XX:XX:XX:XX:XX:XX Workqueue: events_freezable ieee80211_restart_work [mac80211] (unwind_backtrace) from (show_stack+0x10/0x14) (show_stack) (dump_stack+0x80/0xa0) (dump_stack) (warn_slowpath_common+0x68/0x8c) (warn_slowpath_common) (warn_slowpath_null+0x18/0x20) (warn_slowpath_null) (ieee80211_enable_keys+0x88/0x154 [mac80211]) (ieee80211_enable_keys) (ieee80211_reconfig+0xc90/0x19c8 [mac80211]) (ieee80211_reconfig]) (ieee80211_restart_work+0x8c/0xa0 [mac80211]) (ieee80211_restart_work) (process_one_work+0x284/0x488) (process_one_work) (worker_thread+0x228/0x360) (worker_thread) (kthread+0xd8/0xec) (kthread) (ret_from_fork+0x14/0x24) Also while bringing down the AP VAP, WARN_ONs and errors related to peer removal were observed. ath10k_pci : failed to clear all peer wep keys for vdev 0: -2 ath10k_pci : failed to disassociate station: 8c:fd:f0:0a:8c:f5 vdev 0: -2 (unwind_backtrace) (show_stack+0x10/0x14) (show_stack) (dump_stack+0x80/0xa0) (dump_stack) (warn_slowpath_common+0x68/0x8c) (warn_slowpath_common) (warn_slowpath_null+0x18/0x20) (warn_slowpath_null) (sta_set_sinfo+0xb98/0xc9c [mac80211]) (sta_set_sinfo [mac80211]) (__sta_info_flush+0xf0/0x134 [mac80211]) (__sta_info_flush [mac80211]) (ieee80211_stop_ap+0xe8/0x390 [mac80211]) (ieee80211_stop_ap [mac80211]) (__cfg80211_stop_ap+0xe0/0x3dc [cfg80211]) (__cfg80211_stop_ap [cfg80211]) (cfg80211_stop_ap+0x30/0x44 [cfg80211]) (cfg80211_stop_ap [cfg80211]) (genl_rcv_msg+0x274/0x30c) (genl_rcv_msg) (netlink_rcv_skb+0x58/0xac) (netlink_rcv_skb) (genl_rcv+0x20/0x34) (genl_rcv) (netlink_unicast+0x11c/0x204) (netlink_unicast) (netlink_sendmsg+0x30c/0x370) (netlink_sendmsg) (sock_sendmsg+0x70/0x84) (sock_sendmsg) (___sys_sendmsg.part.3+0x188/0x228) (___sys_sendmsg.part.3) (__sys_sendmsg+0x4c/0x70) (__sys_sendmsg) (ret_fast_syscall+0x0/0x44) These issues got fixed by adding the stations which are tied to AP_VLANs back to the driver. Signed-off-by: Manikanta Pubbisetty Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/mac80211/util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0043256df486..d5c35324df26 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1876,7 +1876,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (!sta->uploaded) continue; - if (sta->sdata->vif.type != NL80211_IFTYPE_AP) + if (sta->sdata->vif.type != NL80211_IFTYPE_AP && + sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN) continue; for (state = IEEE80211_STA_NOTEXIST; From 115b73804426c303961eacf9b6585b1e1f7a4ae7 Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Sun, 8 Jul 2018 09:57:22 +0000 Subject: [PATCH 309/392] nl80211: Add a missing break in parse_station_flags [ Upstream commit 5cf3006cc81d9aa09a10aa781fc065546b12919d ] I was looking at usually suppressed gcc warnings, [-Wimplicit-fallthrough=] in this case: The code definitely looks like a break is missing here. However I am not able to test the NL80211_IFTYPE_MESH_POINT, nor do I actually know what might be :) So please use this patch with caution and only if you are able to do some testing. Signed-off-by: Bernd Edlinger [johannes: looks obvious enough to apply as is, interesting though that it never seems to have been a problem] Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/wireless/nl80211.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f843f704c17c..fefc9a4d3592 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3490,6 +3490,7 @@ static int parse_station_flags(struct genl_info *info, params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) | BIT(NL80211_STA_FLAG_MFP) | BIT(NL80211_STA_FLAG_AUTHORIZED); + break; default: return -EINVAL; } From ad020ae8a46bbc2ad6b14c83597b8f9263e3c3ca Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Wed, 11 Jul 2018 22:09:52 +0530 Subject: [PATCH 310/392] scsi: libiscsi: fix possible NULL pointer dereference in case of TMF [ Upstream commit a17037e7d59075053b522048742a08ac9500bde8 ] In iscsi_check_tmf_restrictions() task->hdr is dereferenced to print the opcode, it is possible that task->hdr is NULL. There are two cases based on opcode argument: 1. ISCSI_OP_SCSI_CMD - In this case alloc_pdu() is called after iscsi_check_tmf_restrictions() iscsi_prep_scsi_cmd_pdu() -> iscsi_check_tmf_restrictions() -> alloc_pdu(). Transport drivers allocate memory for iSCSI hdr in alloc_pdu() and assign it to task->hdr. In case of TMF task->hdr will be NULL resulting in NULL pointer dereference. 2. ISCSI_OP_SCSI_DATA_OUT - In this case transport driver can free the memory for iSCSI hdr after transmitting the pdu so task->hdr can be NULL or invalid. This patch fixes this issue by removing task->hdr->opcode from the printk statement. Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libiscsi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 9ca83ebef776..857bf9417817 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -283,11 +283,11 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode) */ if (opcode != ISCSI_OP_SCSI_DATA_OUT) { iscsi_conn_printk(KERN_INFO, conn, - "task [op %x/%x itt " + "task [op %x itt " "0x%x/0x%x] " "rejected.\n", - task->hdr->opcode, opcode, - task->itt, task->hdr_itt); + opcode, task->itt, + task->hdr_itt); return -EACCES; } /* @@ -296,10 +296,10 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode) */ if (conn->session->fast_abort) { iscsi_conn_printk(KERN_INFO, conn, - "task [op %x/%x itt " + "task [op %x itt " "0x%x/0x%x] fast abort.\n", - task->hdr->opcode, opcode, - task->itt, task->hdr_itt); + opcode, task->itt, + task->hdr_itt); return -EACCES; } break; From ce7c57f67930a297dd576217363c4a1fee5b8c6c Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 11 Apr 2018 17:31:35 +0200 Subject: [PATCH 311/392] drm/imx: imx-ldb: disable LDB on driver bind [ Upstream commit b58262396fabd43dc869b576e3defdd23b32fe94 ] The LVDS signal integrity is only guaranteed when the correct enable sequence (first IPU DI, then LDB) is used. If the LDB display output was active before the imx-drm driver is loaded (like when a bootsplash was active) the DI will be disabled by the full IPU reset we do when loading the driver. The LDB control registers are not part of the IPU range and thus will remain unchanged. This leads to the LDB still being active when the DI is getting enabled, effectively reversing the required enable sequence. Fix this by also disabling the LDB on driver bind. Signed-off-by: Lucas Stach Signed-off-by: Philipp Zabel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/imx-drm/imx-ldb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c index 4662e00b456a..c44eb82f892d 100644 --- a/drivers/staging/imx-drm/imx-ldb.c +++ b/drivers/staging/imx-drm/imx-ldb.c @@ -460,6 +460,9 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) return PTR_ERR(imx_ldb->regmap); } + /* disable LDB by resetting the control register to POR default */ + regmap_write(imx_ldb->regmap, IOMUXC_GPR2, 0); + imx_ldb->dev = dev; if (of_id) From 2d72c0a9616b1107044ce908694606549633ba16 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 11 Apr 2018 17:31:36 +0200 Subject: [PATCH 312/392] drm/imx: imx-ldb: check if channel is enabled before printing warning [ Upstream commit c80d673b91a6c81d765864e10f2b15110ee900ad ] If the second LVDS channel has been disabled in the DT when using dual-channel mode we should not print a warning. Signed-off-by: Lucas Stach Signed-off-by: Philipp Zabel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/imx-drm/imx-ldb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c index c44eb82f892d..62fdd670509c 100644 --- a/drivers/staging/imx-drm/imx-ldb.c +++ b/drivers/staging/imx-drm/imx-ldb.c @@ -500,14 +500,14 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) if (ret || i < 0 || i > 1) return -EINVAL; + if (!of_device_is_available(child)) + continue; + if (dual && i > 0) { dev_warn(dev, "dual-channel mode, ignoring second output\n"); continue; } - if (!of_device_is_available(child)) - continue; - channel = &imx_ldb->channel[i]; channel->ldb = imx_ldb; channel->chno = i; From c51c58d75d8f0885952a9f84f123fdb941b7e290 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Wed, 20 Jun 2018 11:54:53 +0800 Subject: [PATCH 313/392] usb: gadget: r8a66597: Fix two possible sleep-in-atomic-context bugs in init_controller() [ Upstream commit 0602088b10a7c0b4e044a810678ef93d7cc5bf48 ] The driver may sleep with holding a spinlock. The function call paths (from bottom to top) in Linux-4.16.7 are: [FUNC] msleep drivers/usb/gadget/udc/r8a66597-udc.c, 839: msleep in init_controller drivers/usb/gadget/udc/r8a66597-udc.c, 96: init_controller in r8a66597_usb_disconnect drivers/usb/gadget/udc/r8a66597-udc.c, 93: spin_lock in r8a66597_usb_disconnect [FUNC] msleep drivers/usb/gadget/udc/r8a66597-udc.c, 835: msleep in init_controller drivers/usb/gadget/udc/r8a66597-udc.c, 96: init_controller in r8a66597_usb_disconnect drivers/usb/gadget/udc/r8a66597-udc.c, 93: spin_lock in r8a66597_usb_disconnect To fix these bugs, msleep() is replaced with mdelay(). This bug is found by my static analysis tool (DSAC-2) and checked by my code review. Signed-off-by: Jia-Ju Bai Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/r8a66597-udc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index f8186613b53e..c223a6dc9c7a 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -835,11 +835,11 @@ static void init_controller(struct r8a66597 *r8a66597) r8a66597_bset(r8a66597, XCKE, SYSCFG0); - msleep(3); + mdelay(3); r8a66597_bset(r8a66597, PLLC, SYSCFG0); - msleep(1); + mdelay(1); r8a66597_bset(r8a66597, SCKE, SYSCFG0); From 97f07e5888aa676b05e0fb17f0b18f929bc6e4e3 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Wed, 20 Jun 2018 11:55:08 +0800 Subject: [PATCH 314/392] usb: gadget: r8a66597: Fix a possible sleep-in-atomic-context bugs in r8a66597_queue() [ Upstream commit f36b507c14c4b6e634463a610294e9cb0065c8ea ] The driver may sleep in an interrupt handler. The function call path (from bottom to top) in Linux-4.16.7 is: [FUNC] r8a66597_queue(GFP_KERNEL) drivers/usb/gadget/udc/r8a66597-udc.c, 1193: r8a66597_queue in get_status drivers/usb/gadget/udc/r8a66597-udc.c, 1301: get_status in setup_packet drivers/usb/gadget/udc/r8a66597-udc.c, 1381: setup_packet in irq_control_stage drivers/usb/gadget/udc/r8a66597-udc.c, 1508: irq_control_stage in r8a66597_irq (interrupt handler) To fix this bug, GFP_KERNEL is replaced with GFP_ATOMIC. This bug is found by my static analysis tool (DSAC-2) and checked by my code review. Signed-off-by: Jia-Ju Bai Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/r8a66597-udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index c223a6dc9c7a..4848607b0798 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1193,7 +1193,7 @@ __acquires(r8a66597->lock) r8a66597->ep0_req->length = 2; /* AV: what happens if we get called again before that gets through? */ spin_unlock(&r8a66597->lock); - r8a66597_queue(r8a66597->gadget.ep0, r8a66597->ep0_req, GFP_KERNEL); + r8a66597_queue(r8a66597->gadget.ep0, r8a66597->ep0_req, GFP_ATOMIC); spin_lock(&r8a66597->lock); } From a438b32e424c9ebdda48244cb1620571b1cab590 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 15 Jul 2018 10:37:37 -0700 Subject: [PATCH 315/392] usb/phy: fix PPC64 build errors in phy-fsl-usb.c [ Upstream commit a39ba90a1cc7010edb0a7132e1b67f3d80b994e9 ] Fix build errors when built for PPC64: These variables are only used on PPC32 so they don't need to be initialized for PPC64. ../drivers/usb/phy/phy-fsl-usb.c: In function 'usb_otg_start': ../drivers/usb/phy/phy-fsl-usb.c:865:3: error: '_fsl_readl' undeclared (first use in this function); did you mean 'fsl_readl'? _fsl_readl = _fsl_readl_be; ../drivers/usb/phy/phy-fsl-usb.c:865:16: error: '_fsl_readl_be' undeclared (first use in this function); did you mean 'fsl_readl'? _fsl_readl = _fsl_readl_be; ../drivers/usb/phy/phy-fsl-usb.c:866:3: error: '_fsl_writel' undeclared (first use in this function); did you mean 'fsl_writel'? _fsl_writel = _fsl_writel_be; ../drivers/usb/phy/phy-fsl-usb.c:866:17: error: '_fsl_writel_be' undeclared (first use in this function); did you mean 'fsl_writel'? _fsl_writel = _fsl_writel_be; ../drivers/usb/phy/phy-fsl-usb.c:868:16: error: '_fsl_readl_le' undeclared (first use in this function); did you mean 'fsl_readl'? _fsl_readl = _fsl_readl_le; ../drivers/usb/phy/phy-fsl-usb.c:869:17: error: '_fsl_writel_le' undeclared (first use in this function); did you mean 'fsl_writel'? _fsl_writel = _fsl_writel_le; and the sysfs "show" function return type should be ssize_t, not int: ../drivers/usb/phy/phy-fsl-usb.c:1042:49: error: initialization of 'ssize_t (*)(struct device *, struct device_attribute *, char *)' {aka 'long int (*)(struct device *, struct device_attribute *, char *)'} from incompatible pointer type 'int (*)(struct device *, struct device_attribute *, char *)' [-Werror=incompatible-pointer-types] static DEVICE_ATTR(fsl_usb2_otg_state, S_IRUGO, show_fsl_usb2_otg_state, NULL); Signed-off-by: Randy Dunlap Cc: Felipe Balbi Cc: linux-usb@vger.kernel.org Cc: Michael Ellerman Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-fsl-usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index f1ea5990a50a..c9c5b539eb5e 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -913,6 +913,7 @@ int usb_otg_start(struct platform_device *pdev) if (pdata->init && pdata->init(pdev) != 0) return -EINVAL; +#ifdef CONFIG_PPC32 if (pdata->big_endian_mmio) { _fsl_readl = _fsl_readl_be; _fsl_writel = _fsl_writel_be; @@ -920,6 +921,7 @@ int usb_otg_start(struct platform_device *pdev) _fsl_readl = _fsl_readl_le; _fsl_writel = _fsl_writel_le; } +#endif /* request irq */ p_otg->irq = platform_get_irq(pdev, 0); @@ -1010,7 +1012,7 @@ int usb_otg_start(struct platform_device *pdev) /* * state file in sysfs */ -static int show_fsl_usb2_otg_state(struct device *dev, +static ssize_t show_fsl_usb2_otg_state(struct device *dev, struct device_attribute *attr, char *buf) { struct otg_fsm *fsm = &fsl_otg_dev->fsm; From 54615755396be98de0d13eb10dca02cc3eb854b9 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Tue, 10 Jul 2018 16:01:45 +0200 Subject: [PATCH 316/392] tools: usb: ffs-test: Fix build on big endian systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a2b22dddc7bb6110ac3b5ed1a60aa9279836fadb ] The tools/usb/ffs-test.c file defines cpu_to_le16/32 by using the C library htole16/32 function calls. However, cpu_to_le16/32 are used when initializing structures, i.e in a context where a function call is not allowed. It works fine on little endian systems because htole16/32 are defined by the C library as no-ops. But on big-endian systems, they are actually doing something, which might involve calling a function, causing build failures, such as: ffs-test.c:48:25: error: initializer element is not constant #define cpu_to_le32(x) htole32(x) ^~~~~~~ ffs-test.c:128:12: note: in expansion of macro ‘cpu_to_le32’ .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2), ^~~~~~~~~~~ To solve this, we code cpu_to_le16/32 in a way that allows them to be used when initializing structures. This fix was imported from meta-openembedded/android-tools/fix-big-endian-build.patch written by Thomas Petazzoni . CC: Thomas Petazzoni Signed-off-by: Peter Senna Tschudin Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/usb/ffs-test.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c index 88d5e71be044..47dfa0b0fcd7 100644 --- a/tools/usb/ffs-test.c +++ b/tools/usb/ffs-test.c @@ -44,12 +44,25 @@ /******************** Little Endian Handling ********************************/ -#define cpu_to_le16(x) htole16(x) -#define cpu_to_le32(x) htole32(x) +/* + * cpu_to_le16/32 are used when initializing structures, a context where a + * function call is not allowed. To solve this, we code cpu_to_le16/32 in a way + * that allows them to be used when initializing structures. + */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#else +#define cpu_to_le16(x) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8)) +#define cpu_to_le32(x) \ + ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | \ + (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24)) +#endif + #define le32_to_cpu(x) le32toh(x) #define le16_to_cpu(x) le16toh(x) - /******************** Messages and Errors ***********************************/ static const char argv0[] = "ffs-test"; From 2b8e010e3a0c12e88adad7017f03aefd9532d2e3 Mon Sep 17 00:00:00 2001 From: Eugeniu Rosca Date: Mon, 2 Jul 2018 23:46:47 +0200 Subject: [PATCH 317/392] usb: gadget: f_uac2: fix endianness of 'struct cntrl_*_lay3' [ Upstream commit eec24f2a0d4dc3b1d95a3ccd2feb523ede3ba775 ] The list [1] of commits doing endianness fixes in USB subsystem is long due to below quote from USB spec Revision 2.0 from April 27, 2000: ------------ 8.1 Byte/Bit Ordering Multiple byte fields in standard descriptors, requests, and responses are interpreted as and moved over the bus in little-endian order, i.e. LSB to MSB. ------------ This commit belongs to the same family. [1] Example of endianness fixes in USB subsystem: commit 14e1d56cbea6 ("usb: gadget: f_uac2: endianness fixes.") commit 42370b821168 ("usb: gadget: f_uac1: endianness fixes.") commit 63afd5cc7877 ("USB: chaoskey: fix Alea quirk on big-endian hosts") commit 74098c4ac782 ("usb: gadget: acm: fix endianness in notifications") commit cdd7928df0d2 ("ACM gadget: fix endianness in notifications") commit 323ece54e076 ("cdc-wdm: fix endianness bug in debug statements") commit e102609f1072 ("usb: gadget: uvc: Fix endianness mismatches") list goes on Fixes: 132fcb460839 ("usb: gadget: Add Audio Class 2.0 Driver") Signed-off-by: Eugeniu Rosca Reviewed-by: Ruslan Bilovol Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_uac2.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 3a03cbb79c35..cce668c5ece4 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -941,14 +941,14 @@ static struct usb_descriptor_header *hs_audio_desc[] = { }; struct cntrl_cur_lay3 { - __u32 dCUR; + __le32 dCUR; }; struct cntrl_range_lay3 { - __u16 wNumSubRanges; - __u32 dMIN; - __u32 dMAX; - __u32 dRES; + __le16 wNumSubRanges; + __le32 dMIN; + __le32 dMAX; + __le32 dRES; } __packed; static inline void @@ -1274,9 +1274,9 @@ in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) struct cntrl_cur_lay3 c; if (entity_id == USB_IN_CLK_ID) - c.dCUR = p_srate; + c.dCUR = cpu_to_le32(p_srate); else if (entity_id == USB_OUT_CLK_ID) - c.dCUR = c_srate; + c.dCUR = cpu_to_le32(c_srate); value = min_t(unsigned, w_length, sizeof c); memcpy(req->buf, &c, value); @@ -1314,15 +1314,15 @@ in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr) if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { if (entity_id == USB_IN_CLK_ID) - r.dMIN = p_srate; + r.dMIN = cpu_to_le32(p_srate); else if (entity_id == USB_OUT_CLK_ID) - r.dMIN = c_srate; + r.dMIN = cpu_to_le32(c_srate); else return -EOPNOTSUPP; r.dMAX = r.dMIN; r.dRES = 0; - r.wNumSubRanges = 1; + r.wNumSubRanges = cpu_to_le16(1); value = min_t(unsigned, w_length, sizeof r); memcpy(req->buf, &r, value); From 944dbf3b36cffd8d180c46545a5e5dc66f360d72 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 20 Jul 2018 14:47:03 -0400 Subject: [PATCH 318/392] tools/power turbostat: fix -S on UP systems [ Upstream commit 9d83601a9cc1884d1b5706ee2acc661d558c6838 ] The -S (system summary) option failed to print any data on a 1-processor system. Reported-by: Artem Bityutskiy Signed-off-by: Len Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/power/x86/turbostat/turbostat.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 5b1b807265a1..195ddd950ba2 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -605,9 +605,7 @@ void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_ if (!printed || !summary_only) print_header(); - if (topo.num_cpus > 1) - format_counters(&average.threads, &average.cores, - &average.packages); + format_counters(&average.threads, &average.cores, &average.packages); printed = 1; From 4794000789d6007de094dbbeb37feca05e05c0e2 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 19 Jul 2018 10:27:13 +0800 Subject: [PATCH 319/392] net: caif: Add a missing rcu_read_unlock() in caif_flow_cb [ Upstream commit 64119e05f7b31e83e2555f6782e6cdc8f81c63f4 ] Add a missing rcu_read_unlock in the error path Fixes: c95567c80352 ("caif: added check for potential null return") Signed-off-by: YueHaibing Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/caif/caif_dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index edbca468fa73..d8e56a5c1a94 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -131,8 +131,10 @@ static void caif_flow_cb(struct sk_buff *skb) caifd = caif_get(skb->dev); WARN_ON(caifd == NULL); - if (caifd == NULL) + if (!caifd) { + rcu_read_unlock(); return; + } caifd_hold(caifd); rcu_read_unlock(); From 4dafaff5d7584e7fabb13ace1068fc543a956094 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 20 Jul 2018 19:30:57 +0200 Subject: [PATCH 320/392] atl1c: reserve min skb headroom [ Upstream commit 6e56830776828d8ca9897fc4429eeab47c3bb432 ] Got crash report with following backtrace: BUG: unable to handle kernel paging request at ffff8801869daffe RIP: 0010:[] [] ip6_finish_output2+0x394/0x4c0 RSP: 0018:ffff880186c83a98 EFLAGS: 00010283 RAX: ffff8801869db00e ... [] ip6_finish_output+0x8c/0xf0 [] ip6_output+0x57/0x100 [] ip6_forward+0x4b9/0x840 [] ip6_rcv_finish+0x66/0xc0 [] ipv6_rcv+0x319/0x530 [] netif_receive_skb+0x1c/0x70 [] atl1c_clean+0x1ec/0x310 [atl1c] ... The bad access is in neigh_hh_output(), at skb->data - 16 (HH_DATA_MOD). atl1c driver provided skb with no headroom, so 14 bytes (ethernet header) got pulled, but then 16 are copied. Reserve NET_SKB_PAD bytes headroom, like netdev_alloc_skb(). Compile tested only; I lack hardware. Fixes: 7b7017642199 ("atl1c: Fix misuse of netdev_alloc_skb in refilling rx ring") Signed-off-by: Florian Westphal Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 067f2cb9b215..ae05c8734d49 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -1674,6 +1674,7 @@ static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter) skb = build_skb(page_address(page) + adapter->rx_page_offset, adapter->rx_frag_size); if (likely(skb)) { + skb_reserve(skb, NET_SKB_PAD); adapter->rx_page_offset += adapter->rx_frag_size; if (adapter->rx_page_offset >= PAGE_SIZE) adapter->rx_page = NULL; From b725b8a218bc103e5afe574b908533f7686295c6 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 9 Jul 2018 21:16:40 +0200 Subject: [PATCH 321/392] can: mpc5xxx_can: check of_iomap return before use [ Upstream commit b5c1a23b17e563b656cc9bb76ce5323b997d90e8 ] of_iomap() can return NULL so that return needs to be checked and NULL treated as failure. While at it also take care of the missing of_node_put() in the error path. Signed-off-by: Nicholas Mc Guire Fixes: commit afa17a500a36 ("net/can: add driver for mscan family & mpc52xx_mscan") Signed-off-by: Marc Kleine-Budde Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/mscan/mpc5xxx_can.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index 44725296f72a..655a387eb9ad 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -86,6 +86,11 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, return 0; } cdm = of_iomap(np_cdm, 0); + if (!cdm) { + of_node_put(np_cdm); + dev_err(&ofdev->dev, "can't map clock node!\n"); + return 0; + } if (in_8(&cdm->ipb_clk_sel) & 0x1) freq *= 2; From da1ab9d3f0f858c6f7c6c813b8cab06657448f9b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 23 Jul 2018 14:39:33 -0700 Subject: [PATCH 322/392] media: staging: omap4iss: Include asm/cacheflush.h after generic includes [ Upstream commit 0894da849f145af51bde88a6b84f95b9c9e0bc66 ] Including asm/cacheflush.h first results in the following build error when trying to build sparc32:allmodconfig, because 'struct page' has not been declared, and the function declaration ends up creating a separate (private) declaration of struct page (as a result of function arguments being in the scope of the function declaration and definition, not in global scope). The C scoping rules do not just affect variable visibility, they also affect type declaration visibility. The end result is that when the actual call site is seen in , the 'struct page' type in the caller is not the same 'struct page' that the function was declared with, resulting in: In file included from arch/sparc/include/asm/page.h:10:0, ... from drivers/staging/media/omap4iss/iss_video.c:15: include/linux/highmem.h: In function 'clear_user_highpage': include/linux/highmem.h:137:31: error: passing argument 1 of 'sparc_flush_page_to_ram' from incompatible pointer type Include generic includes files first to fix the problem. Fixes: fc96d58c10162 ("[media] v4l: omap4iss: Add support for OMAP4 camera interface - Video devices") Suggested-by: Linus Torvalds Acked-by: David S. Miller Cc: Randy Dunlap Signed-off-by: Guenter Roeck [ Added explanation of C scope rules - Linus ] Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/media/omap4iss/iss_video.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 5d6250337fec..4f84de43de7c 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -11,7 +11,6 @@ * (at your option) any later version. */ -#include #include #include #include @@ -22,6 +21,8 @@ #include #include +#include + #include "iss_video.h" #include "iss.h" From 73b89b6f951f63b0bdecc217f29fe0f1d9f7c2f4 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Tue, 24 Jul 2018 02:43:52 -0700 Subject: [PATCH 323/392] bnx2x: Fix invalid memory access in rss hash config path. [ Upstream commit ae2dcb28c24794a87e424a726a1cf1a61980f52d ] Rx hash/filter table configuration uses rss_conf_obj to configure filters in the hardware. This object is initialized only when the interface is brought up. This patch adds driver changes to configure rss params only when the device is in opened state. In port disabled case, the config will be cached in the driver structure which will be applied in the successive load path. Please consider applying it to 'net' branch. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 1edc931b1458..2a518c998ecc 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -3296,14 +3296,18 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info) DP(BNX2X_MSG_ETHTOOL, "rss re-configured, UDP 4-tupple %s\n", udp_rss_requested ? "enabled" : "disabled"); - return bnx2x_rss(bp, &bp->rss_conf_obj, false, true); + if (bp->state == BNX2X_STATE_OPEN) + return bnx2x_rss(bp, &bp->rss_conf_obj, false, + true); } else if ((info->flow_type == UDP_V6_FLOW) && (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) { bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested; DP(BNX2X_MSG_ETHTOOL, "rss re-configured, UDP 4-tupple %s\n", udp_rss_requested ? "enabled" : "disabled"); - return bnx2x_rss(bp, &bp->rss_conf_obj, false, true); + if (bp->state == BNX2X_STATE_OPEN) + return bnx2x_rss(bp, &bp->rss_conf_obj, false, + true); } return 0; @@ -3401,7 +3405,10 @@ static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir, bp->rss_conf_obj.ind_table[i] = indir[i] + bp->fp->cl_id; } - return bnx2x_config_rss_eth(bp, false); + if (bp->state == BNX2X_STATE_OPEN) + return bnx2x_config_rss_eth(bp, false); + + return 0; } /** From 903d5b843dc6b9f25fe35033c0aa376be133c8b4 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Tue, 24 Jul 2018 10:09:53 +0530 Subject: [PATCH 324/392] net: axienet: Fix double deregister of mdio [ Upstream commit 03bc7cab7d7218088412a75e141696a89059ab00 ] If the registration fails then mdio_unregister is called. However at unbind the unregister ia attempted again resulting in the below crash [ 73.544038] kernel BUG at drivers/net/phy/mdio_bus.c:415! [ 73.549362] Internal error: Oops - BUG: 0 [#1] SMP [ 73.554127] Modules linked in: [ 73.557168] CPU: 0 PID: 2249 Comm: sh Not tainted 4.14.0 #183 [ 73.562895] Hardware name: xlnx,zynqmp (DT) [ 73.567062] task: ffffffc879e41180 task.stack: ffffff800cbe0000 [ 73.572973] PC is at mdiobus_unregister+0x84/0x88 [ 73.577656] LR is at axienet_mdio_teardown+0x18/0x30 [ 73.582601] pc : [] lr : [] pstate: 20000145 [ 73.589981] sp : ffffff800cbe3c30 [ 73.593277] x29: ffffff800cbe3c30 x28: ffffffc879e41180 [ 73.598573] x27: ffffff8008a21000 x26: 0000000000000040 [ 73.603868] x25: 0000000000000124 x24: ffffffc879efe920 [ 73.609164] x23: 0000000000000060 x22: ffffffc879e02000 [ 73.614459] x21: ffffffc879e02800 x20: ffffffc87b0b8870 [ 73.619754] x19: ffffffc879e02800 x18: 000000000000025d [ 73.625050] x17: 0000007f9a719ad0 x16: ffffff8008195bd8 [ 73.630345] x15: 0000007f9a6b3d00 x14: 0000000000000010 [ 73.635640] x13: 74656e7265687465 x12: 0000000000000030 [ 73.640935] x11: 0000000000000030 x10: 0101010101010101 [ 73.646231] x9 : 241f394f42533300 x8 : ffffffc8799f6e98 [ 73.651526] x7 : ffffffc8799f6f18 x6 : ffffffc87b0ba318 [ 73.656822] x5 : ffffffc87b0ba498 x4 : 0000000000000000 [ 73.662117] x3 : 0000000000000000 x2 : 0000000000000008 [ 73.667412] x1 : 0000000000000004 x0 : ffffffc8799f4000 [ 73.672708] Process sh (pid: 2249, stack limit = 0xffffff800cbe0000) Fix the same by making the bus NULL on unregister. Signed-off-by: Shubhrajyoti Datta Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c index 3b67d60d4378..bc42a1d7a43f 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c @@ -219,6 +219,7 @@ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np) ret = of_mdiobus_register(bus, np1); if (ret) { mdiobus_free(bus); + lp->mii_bus = NULL; return ret; } return 0; From a60d0786f758051c0786a36e69ad07fcf6917b44 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Modukuri Date: Wed, 25 Jul 2018 14:31:20 +0100 Subject: [PATCH 325/392] fscache: Allow cancelled operations to be enqueued [ Upstream commit d0eb06afe712b7b103b6361f40a9a0c638524669 ] Alter the state-check assertion in fscache_enqueue_operation() to allow cancelled operations to be given processing time so they can be cleaned up. Also fix a debugging statement that was requiring such operations to have an object assigned. Fixes: 9ae326a69004 ("CacheFiles: A cache that backs onto a mounted filesystem") Reported-by: Kiran Kumar Modukuri Signed-off-by: David Howells Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/fscache/operation.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index e7b87a0e5185..deac2e89d176 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c @@ -37,7 +37,8 @@ void fscache_enqueue_operation(struct fscache_operation *op) ASSERT(op->processor != NULL); ASSERT(fscache_object_is_available(op->object)); ASSERTCMP(atomic_read(&op->usage), >, 0); - ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); + ASSERTIFCMP(op->state != FSCACHE_OP_ST_IN_PROGRESS, + op->state, ==, FSCACHE_OP_ST_CANCELLED); fscache_stat(&fscache_n_op_enqueue); switch (op->flags & FSCACHE_OP_TYPE) { @@ -401,7 +402,8 @@ void fscache_put_operation(struct fscache_operation *op) struct fscache_cache *cache; _enter("{OBJ%x OP%x,%d}", - op->object->debug_id, op->debug_id, atomic_read(&op->usage)); + op->object ? op->object->debug_id : 0, + op->debug_id, atomic_read(&op->usage)); ASSERTCMP(atomic_read(&op->usage), >, 0); From 4eabf1e295373af45eb0ed2048aa7eb619ec3082 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Modukuri Date: Tue, 18 Jul 2017 16:25:49 -0700 Subject: [PATCH 326/392] cachefiles: Fix refcounting bug in backing-file read monitoring [ Upstream commit 934140ab028713a61de8bca58c05332416d037d1 ] cachefiles_read_waiter() has the right to access a 'monitor' object by virtue of being called under the waitqueue lock for one of the pages in its purview. However, it has no ref on that monitor object or on the associated operation. What it is allowed to do is to move the monitor object to the operation's to_do list, but once it drops the work_lock, it's actually no longer permitted to access that object. However, it is trying to enqueue the retrieval operation for processing - but it can only do this via a pointer in the monitor object, something it shouldn't be doing. If it doesn't enqueue the operation, the operation may not get processed. If the order is flipped so that the enqueue is first, then it's possible for the work processor to look at the to_do list before the monitor is enqueued upon it. Fix this by getting a ref on the operation so that we can trust that it will still be there once we've added the monitor to the to_do list and dropped the work_lock. The op can then be enqueued after the lock is dropped. The bug can manifest in one of a couple of ways. The first manifestation looks like: FS-Cache: FS-Cache: Assertion failed FS-Cache: 6 == 5 is false ------------[ cut here ]------------ kernel BUG at fs/fscache/operation.c:494! RIP: 0010:fscache_put_operation+0x1e3/0x1f0 ... fscache_op_work_func+0x26/0x50 process_one_work+0x131/0x290 worker_thread+0x45/0x360 kthread+0xf8/0x130 ? create_worker+0x190/0x190 ? kthread_cancel_work_sync+0x10/0x10 ret_from_fork+0x1f/0x30 This is due to the operation being in the DEAD state (6) rather than INITIALISED, COMPLETE or CANCELLED (5) because it's already passed through fscache_put_operation(). The bug can also manifest like the following: kernel BUG at fs/fscache/operation.c:69! ... [exception RIP: fscache_enqueue_operation+246] ... #7 [ffff883fff083c10] fscache_enqueue_operation at ffffffffa0b793c6 #8 [ffff883fff083c28] cachefiles_read_waiter at ffffffffa0b15a48 #9 [ffff883fff083c48] __wake_up_common at ffffffff810af028 I'm not entirely certain as to which is line 69 in Lei's kernel, so I'm not entirely clear which assertion failed. Fixes: 9ae326a69004 ("CacheFiles: A cache that backs onto a mounted filesystem") Reported-by: Lei Xue Reported-by: Vegard Nossum Reported-by: Anthony DeRobertis Reported-by: NeilBrown Reported-by: Daniel Axtens Reported-by: Kiran Kumar Modukuri Signed-off-by: David Howells Reviewed-by: Daniel Axtens Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/cachefiles/rdwr.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c index 616db0e77b44..a899e69cd5fd 100644 --- a/fs/cachefiles/rdwr.c +++ b/fs/cachefiles/rdwr.c @@ -27,6 +27,7 @@ static int cachefiles_read_waiter(wait_queue_t *wait, unsigned mode, struct cachefiles_one_read *monitor = container_of(wait, struct cachefiles_one_read, monitor); struct cachefiles_object *object; + struct fscache_retrieval *op = monitor->op; struct wait_bit_key *key = _key; struct page *page = wait->private; @@ -51,16 +52,22 @@ static int cachefiles_read_waiter(wait_queue_t *wait, unsigned mode, list_del(&wait->task_list); /* move onto the action list and queue for FS-Cache thread pool */ - ASSERT(monitor->op); + ASSERT(op); - object = container_of(monitor->op->op.object, - struct cachefiles_object, fscache); + /* We need to temporarily bump the usage count as we don't own a ref + * here otherwise cachefiles_read_copier() may free the op between the + * monitor being enqueued on the op->to_do list and the op getting + * enqueued on the work queue. + */ + fscache_get_retrieval(op); + object = container_of(op->op.object, struct cachefiles_object, fscache); spin_lock(&object->work_lock); - list_add_tail(&monitor->op_link, &monitor->op->to_do); + list_add_tail(&monitor->op_link, &op->to_do); spin_unlock(&object->work_lock); - fscache_enqueue_retrieval(monitor->op); + fscache_enqueue_retrieval(op); + fscache_put_retrieval(op); return 0; } From 582db66cad1b0c02c9cf0a5d955dcfa56fa6e7f7 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Modukuri Date: Thu, 21 Jun 2018 13:25:53 -0700 Subject: [PATCH 327/392] cachefiles: Wait rather than BUG'ing on "Unexpected object collision" [ Upstream commit c2412ac45a8f8f1cd582723c1a139608694d410d ] If we meet a conflicting object that is marked FSCACHE_OBJECT_IS_LIVE in the active object tree, we have been emitting a BUG after logging information about it and the new object. Instead, we should wait for the CACHEFILES_OBJECT_ACTIVE flag to be cleared on the old object (or return an error). The ACTIVE flag should be cleared after it has been removed from the active object tree. A timeout of 60s is used in the wait, so we shouldn't be able to get stuck there. Fixes: 9ae326a69004 ("CacheFiles: A cache that backs onto a mounted filesystem") Signed-off-by: Kiran Kumar Modukuri Signed-off-by: David Howells Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/cachefiles/namei.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index e12f189d539b..80ed75bde04a 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -193,7 +193,6 @@ static int cachefiles_mark_object_active(struct cachefiles_cache *cache, pr_err("\n"); pr_err("Error: Unexpected object collision\n"); cachefiles_printk_object(object, xobject); - BUG(); } atomic_inc(&xobject->usage); write_unlock(&cache->active_lock); From fdb2cd0ff6baa3fbe764eb02f51e52e71a19c420 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 14 Jul 2018 01:28:44 +0900 Subject: [PATCH 328/392] selftests/ftrace: Add snapshot and tracing_on test case [ Upstream commit 82f4f3e69c5c29bce940dd87a2c0f16c51d48d17 ] Add a testcase for checking snapshot and tracing_on relationship. This ensures that the snapshotting doesn't affect current tracing on/off settings. Link: http://lkml.kernel.org/r/153149932412.11274.15289227592627901488.stgit@devbox Cc: Tom Zanussi Cc: Hiraku Toyooka Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Shuah Khan Cc: linux-kselftest@vger.kernel.org Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../ftrace/test.d/00basic/snapshot.tc | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/00basic/snapshot.tc diff --git a/tools/testing/selftests/ftrace/test.d/00basic/snapshot.tc b/tools/testing/selftests/ftrace/test.d/00basic/snapshot.tc new file mode 100644 index 000000000000..3b1f45e13a2e --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/00basic/snapshot.tc @@ -0,0 +1,28 @@ +#!/bin/sh +# description: Snapshot and tracing setting +# flags: instance + +[ ! -f snapshot ] && exit_unsupported + +echo "Set tracing off" +echo 0 > tracing_on + +echo "Allocate and take a snapshot" +echo 1 > snapshot + +# Since trace buffer is empty, snapshot is also empty, but allocated +grep -q "Snapshot is allocated" snapshot + +echo "Ensure keep tracing off" +test `cat tracing_on` -eq 0 + +echo "Set tracing on" +echo 1 > tracing_on + +echo "Take a snapshot again" +echo 1 > snapshot + +echo "Ensure keep tracing on" +test `cat tracing_on` -eq 1 + +exit 0 From 33a11da050d9257e5cd9af8ae543aad2627937ec Mon Sep 17 00:00:00 2001 From: Li Wang Date: Thu, 26 Jul 2018 16:37:42 -0700 Subject: [PATCH 329/392] zswap: re-check zswap_is_full() after do zswap_shrink() [ Upstream commit 16e536ef47f567289a5699abee9ff7bb304bc12d ] /sys/../zswap/stored_pages keeps rising in a zswap test with "zswap.max_pool_percent=0" parameter. But it should not compress or store pages any more since there is no space in the compressed pool. Reproduce steps: 1. Boot kernel with "zswap.enabled=1" 2. Set the max_pool_percent to 0 # echo 0 > /sys/module/zswap/parameters/max_pool_percent 3. Do memory stress test to see if some pages have been compressed # stress --vm 1 --vm-bytes $mem_available"M" --timeout 60s 4. Watching the 'stored_pages' number increasing or not The root cause is: When zswap_max_pool_percent is set to 0 via kernel parameter, zswap_is_full() will always return true due to zswap_shrink(). But if the shinking is able to reclain a page successfully the code then proceeds to compressing/storing another page, so the value of stored_pages will keep changing. To solve the issue, this patch adds a zswap_is_full() check again after zswap_shrink() to make sure it's now under the max_pool_percent, and to not compress/store if we reached the limit. Link: http://lkml.kernel.org/r/20180530103936.17812-1-liwang@redhat.com Signed-off-by: Li Wang Acked-by: Dan Streetman Cc: Seth Jennings Cc: Huang Ying Cc: Yu Zhao Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/zswap.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mm/zswap.c b/mm/zswap.c index ea064c1a09ba..8a8dc8b3b858 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -662,6 +662,15 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset, ret = -ENOMEM; goto reject; } + + /* A second zswap_is_full() check after + * zswap_shrink() to make sure it's now + * under the max_pool_percent + */ + if (zswap_is_full()) { + ret = -ENOMEM; + goto reject; + } } /* allocate entry */ From 417ea4338f930e9fc51280196e3cf08bd7cd1ae6 Mon Sep 17 00:00:00 2001 From: Calvin Walton Date: Fri, 27 Jul 2018 07:50:53 -0400 Subject: [PATCH 330/392] tools/power turbostat: Read extended processor family from CPUID [ Upstream commit 5aa3d1a20a233d4a5f1ec3d62da3f19d9afea682 ] This fixes the reported family on modern AMD processors (e.g. Ryzen, which is family 0x17). Previously these processors all showed up as family 0xf. See the document https://support.amd.com/TechDocs/56255_OSRR.pdf section CPUID_Fn00000001_EAX for how to calculate the family from the BaseFamily and ExtFamily values. This matches the code in arch/x86/lib/cpu.c Signed-off-by: Calvin Walton Signed-off-by: Len Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/power/x86/turbostat/turbostat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 195ddd950ba2..f771e09eef33 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -2009,7 +2009,9 @@ void check_cpuid() family = (fms >> 8) & 0xf; model = (fms >> 4) & 0xf; stepping = fms & 0xf; - if (family == 6 || family == 0xf) + if (family == 0xf) + family += (fms >> 20) & 0xff; + if (family >= 6) model += ((fms >> 16) & 0xf) << 4; if (verbose) From af47ed842dd6fec5f1255077afea55e1c6e8d624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 27 Jul 2018 13:13:39 +0200 Subject: [PATCH 331/392] Revert "MIPS: BCM47XX: Enable 74K Core ExternalSync for PCIe erratum" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit d5ea019f8a381f88545bb26993b62ec24a2796b7 ] This reverts commit 2a027b47dba6 ("MIPS: BCM47XX: Enable 74K Core ExternalSync for PCIe erratum"). Enabling ExternalSync caused a regression for BCM4718A1 (used e.g. in Netgear E3000 and ASUS RT-N16): it simply hangs during PCIe initialization. It's likely that BCM4717A1 is also affected. I didn't notice that earlier as the only BCM47XX devices with PCIe I own are: 1) BCM4706 with 2 x 14e4:4331 2) BCM4706 with 14e4:4360 and 14e4:4331 it appears that BCM4706 is unaffected. While BCM5300X-ES300-RDS.pdf seems to document that erratum and its workarounds (according to quotes provided by Tokunori) it seems not even Broadcom follows them. According to the provided info Broadcom should define CONF7_ES in their SDK's mipsinc.h and implement workaround in the si_mips_init(). Checking both didn't reveal such code. It *could* mean Broadcom also had some problems with the given workaround. Signed-off-by: Rafał Miłecki Signed-off-by: Paul Burton Reported-by: Michael Marley Patchwork: https://patchwork.linux-mips.org/patch/20032/ URL: https://bugs.openwrt.org/index.php?do=details&task_id=1688 Cc: Tokunori Ikegami Cc: Hauke Mehrtens Cc: Chris Packham Cc: James Hogan Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/mips/bcm47xx/setup.c | 6 ------ arch/mips/include/asm/mipsregs.h | 3 --- 2 files changed, 9 deletions(-) diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 706bab38479d..c00585d915bc 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -269,12 +269,6 @@ static int __init bcm47xx_cpu_fixes(void) */ if (bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4706) cpu_wait = NULL; - - /* - * BCM47XX Erratum "R10: PCIe Transactions Periodically Fail" - * Enable ExternalSync for sync instruction to take effect - */ - set_c0_config7(MIPS_CONF7_ES); break; #endif } diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 9655d0a47e8c..f38ca68285ea 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -667,8 +667,6 @@ #define MIPS_CONF7_WII (_ULCAST_(1) << 31) #define MIPS_CONF7_RPS (_ULCAST_(1) << 2) -/* ExternalSync */ -#define MIPS_CONF7_ES (_ULCAST_(1) << 8) #define MIPS_CONF7_IAR (_ULCAST_(1) << 10) #define MIPS_CONF7_AR (_ULCAST_(1) << 16) @@ -1865,7 +1863,6 @@ __BUILD_SET_C0(status) __BUILD_SET_C0(cause) __BUILD_SET_C0(config) __BUILD_SET_C0(config5) -__BUILD_SET_C0(config7) __BUILD_SET_C0(intcontrol) __BUILD_SET_C0(intctl) __BUILD_SET_C0(srsmap) From e5b4032baa097fd1d4ca69dba849d7717becdc60 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan Date: Fri, 27 Jul 2018 11:19:29 -0700 Subject: [PATCH 332/392] enic: handle mtu change for vf properly [ Upstream commit ab123fe071c9aa9680ecd62eb080eb26cff4892c ] When driver gets notification for mtu change, driver does not handle it for all RQs. It handles only RQ[0]. Fix is to use enic_change_mtu() interface to change mtu for vf. Signed-off-by: Govindarajulu Varadarajan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/cisco/enic/enic_main.c | 78 +++++++-------------- 1 file changed, 27 insertions(+), 51 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index aa635cbb648f..c6775de7b4f2 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1717,10 +1717,32 @@ static int enic_stop(struct net_device *netdev) return 0; } +static int _enic_change_mtu(struct net_device *netdev, int new_mtu) +{ + bool running = netif_running(netdev); + int err = 0; + + ASSERT_RTNL(); + if (running) { + err = enic_stop(netdev); + if (err) + return err; + } + + netdev->mtu = new_mtu; + + if (running) { + err = enic_open(netdev); + if (err) + return err; + } + + return 0; +} + static int enic_change_mtu(struct net_device *netdev, int new_mtu) { struct enic *enic = netdev_priv(netdev); - int running = netif_running(netdev); if (new_mtu < ENIC_MIN_MTU || new_mtu > ENIC_MAX_MTU) return -EINVAL; @@ -1728,20 +1750,12 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu) if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic)) return -EOPNOTSUPP; - if (running) - enic_stop(netdev); - - netdev->mtu = new_mtu; - if (netdev->mtu > enic->port_mtu) netdev_warn(netdev, - "interface MTU (%d) set higher than port MTU (%d)\n", - netdev->mtu, enic->port_mtu); + "interface MTU (%d) set higher than port MTU (%d)\n", + netdev->mtu, enic->port_mtu); - if (running) - enic_open(netdev); - - return 0; + return _enic_change_mtu(netdev, new_mtu); } static void enic_change_mtu_work(struct work_struct *work) @@ -1749,47 +1763,9 @@ static void enic_change_mtu_work(struct work_struct *work) struct enic *enic = container_of(work, struct enic, change_mtu_work); struct net_device *netdev = enic->netdev; int new_mtu = vnic_dev_mtu(enic->vdev); - int err; - unsigned int i; - - new_mtu = max_t(int, ENIC_MIN_MTU, min_t(int, ENIC_MAX_MTU, new_mtu)); rtnl_lock(); - - /* Stop RQ */ - del_timer_sync(&enic->notify_timer); - - for (i = 0; i < enic->rq_count; i++) - napi_disable(&enic->napi[i]); - - vnic_intr_mask(&enic->intr[0]); - enic_synchronize_irqs(enic); - err = vnic_rq_disable(&enic->rq[0]); - if (err) { - rtnl_unlock(); - netdev_err(netdev, "Unable to disable RQ.\n"); - return; - } - vnic_rq_clean(&enic->rq[0], enic_free_rq_buf); - vnic_cq_clean(&enic->cq[0]); - vnic_intr_clean(&enic->intr[0]); - - /* Fill RQ with new_mtu-sized buffers */ - netdev->mtu = new_mtu; - vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); - /* Need at least one buffer on ring to get going */ - if (vnic_rq_desc_used(&enic->rq[0]) == 0) { - rtnl_unlock(); - netdev_err(netdev, "Unable to alloc receive buffers.\n"); - return; - } - - /* Start RQ */ - vnic_rq_enable(&enic->rq[0]); - napi_enable(&enic->napi[0]); - vnic_intr_unmask(&enic->intr[0]); - enic_notify_timer_start(enic); - + (void)_enic_change_mtu(netdev, new_mtu); rtnl_unlock(); netdev_info(netdev, "interface MTU set as %d\n", netdev->mtu); From 04b68e45e601e86571eb6a441f4bde0735649526 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 26 Jul 2018 20:16:35 -0700 Subject: [PATCH 333/392] arc: fix build errors in arc/include/asm/delay.h [ Upstream commit 2423665ec53f2a29191b35382075e9834288a975 ] Fix build errors in arch/arc/'s delay.h: - add "extern unsigned long loops_per_jiffy;" - add for "u64" In file included from ../drivers/infiniband/hw/cxgb3/cxio_hal.c:32: ../arch/arc/include/asm/delay.h: In function '__udelay': ../arch/arc/include/asm/delay.h:61:12: error: 'u64' undeclared (first use in this function) loops = ((u64) usecs * 4295 * HZ * loops_per_jiffy) >> 32; ^~~ In file included from ../drivers/infiniband/hw/cxgb3/cxio_hal.c:32: ../arch/arc/include/asm/delay.h: In function '__udelay': ../arch/arc/include/asm/delay.h:63:37: error: 'loops_per_jiffy' undeclared (first use in this function) loops = ((u64) usecs * 4295 * HZ * loops_per_jiffy) >> 32; ^~~~~~~~~~~~~~~ Signed-off-by: Randy Dunlap Cc: Vineet Gupta Cc: linux-snps-arc@lists.infradead.org Cc: Elad Kanfi Cc: Leon Romanovsky Cc: Ofer Levi Signed-off-by: Vineet Gupta Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arc/include/asm/delay.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arc/include/asm/delay.h b/arch/arc/include/asm/delay.h index 43de30256981..ee08badc5b91 100644 --- a/arch/arc/include/asm/delay.h +++ b/arch/arc/include/asm/delay.h @@ -17,8 +17,11 @@ #ifndef __ASM_ARC_UDELAY_H #define __ASM_ARC_UDELAY_H +#include #include /* HZ */ +extern unsigned long loops_per_jiffy; + static inline void __delay(unsigned long loops) { __asm__ __volatile__( From 0171efb2288f23ddec8389505f9243e828c0a516 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 26 Jul 2018 20:16:35 -0700 Subject: [PATCH 334/392] arc: fix type warnings in arc/mm/cache.c [ Upstream commit ec837d620c750c0d4996a907c8c4f7febe1bbeee ] Fix type warnings in arch/arc/mm/cache.c. ../arch/arc/mm/cache.c: In function 'flush_anon_page': ../arch/arc/mm/cache.c:1062:55: warning: passing argument 2 of '__flush_dcache_page' makes integer from pointer without a cast [-Wint-conversion] __flush_dcache_page((phys_addr_t)page_address(page), page_address(page)); ^~~~~~~~~~~~~~~~~~ ../arch/arc/mm/cache.c:1013:59: note: expected 'long unsigned int' but argument is of type 'void *' void __flush_dcache_page(phys_addr_t paddr, unsigned long vaddr) ~~~~~~~~~~~~~~^~~~~ Signed-off-by: Randy Dunlap Cc: Vineet Gupta Cc: linux-snps-arc@lists.infradead.org Cc: Elad Kanfi Cc: Leon Romanovsky Cc: Ofer Levi Signed-off-by: Vineet Gupta Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arc/mm/cache_arc700.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c index 2147ca2bc131..51cba86e8cc9 100644 --- a/arch/arc/mm/cache_arc700.c +++ b/arch/arc/mm/cache_arc700.c @@ -642,7 +642,7 @@ void flush_cache_mm(struct mm_struct *mm) void flush_cache_page(struct vm_area_struct *vma, unsigned long u_vaddr, unsigned long pfn) { - unsigned int paddr = pfn << PAGE_SHIFT; + phys_addr_t paddr = pfn << PAGE_SHIFT; u_vaddr &= PAGE_MASK; @@ -662,8 +662,9 @@ void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long u_vaddr) { /* TBD: do we really need to clear the kernel mapping */ - __flush_dcache_page(page_address(page), u_vaddr); - __flush_dcache_page(page_address(page), page_address(page)); + __flush_dcache_page((phys_addr_t)page_address(page), u_vaddr); + __flush_dcache_page((phys_addr_t)page_address(page), + (phys_addr_t)page_address(page)); } From 7ae3f84f252bf40425e2fcba1156dde245810b1c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 1 Aug 2018 18:22:41 +0100 Subject: [PATCH 335/392] drivers: net: lmc: fix case value for target abort error [ Upstream commit afb41bb039656f0cecb54eeb8b2e2088201295f5 ] Current value for a target abort error is 0x010, however, this value should in fact be 0x002. As it stands, the range of error is 0..7 so it is currently never being detected. This bug has been in the driver since the early 2.6.12 days (or before). Detected by CoverityScan, CID#744290 ("Logically dead code") Signed-off-by: Colin Ian King Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wan/lmc/lmc_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index bea0f313a7a8..2b2d01a3e511 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1384,7 +1384,7 @@ static irqreturn_t lmc_interrupt (int irq, void *dev_instance) /*fold00*/ case 0x001: printk(KERN_WARNING "%s: Master Abort (naughty)\n", dev->name); break; - case 0x010: + case 0x002: printk(KERN_WARNING "%s: Target Abort (not so naughty)\n", dev->name); break; default: From ea0f6042693fa876f62d1597de94c65f4cbab2aa Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Tue, 31 Jul 2018 15:46:02 +0200 Subject: [PATCH 336/392] scsi: fcoe: drop frames in ELS LOGO error path [ Upstream commit 63d0e3dffda311e77b9a8c500d59084e960a824a ] Drop the frames in the ELS LOGO error path instead of just returning an error. This fixes the following kmemleak report: unreferenced object 0xffff880064cb1000 (size 424): comm "kworker/0:2", pid 24, jiffies 4294904293 (age 68.504s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<(____ptrval____)>] _fc_frame_alloc+0x2c/0x180 [libfc] [<(____ptrval____)>] fc_lport_enter_logo+0x106/0x360 [libfc] [<(____ptrval____)>] fc_fabric_logoff+0x8c/0xc0 [libfc] [<(____ptrval____)>] fcoe_if_destroy+0x79/0x3b0 [fcoe] [<(____ptrval____)>] fcoe_destroy_work+0xd2/0x170 [fcoe] [<(____ptrval____)>] process_one_work+0x7ff/0x1420 [<(____ptrval____)>] worker_thread+0x87/0xef0 [<(____ptrval____)>] kthread+0x2db/0x390 [<(____ptrval____)>] ret_from_fork+0x35/0x40 [<(____ptrval____)>] 0xffffffffffffffff which can be triggered by issuing echo eth0 > /sys/bus/fcoe/ctlr_destroy Signed-off-by: Johannes Thumshirn Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/fcoe/fcoe_ctlr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 34a1b1f333b4..d5184aa1ace4 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -752,9 +752,9 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, case ELS_LOGO: if (fip->mode == FIP_MODE_VN2VN) { if (fip->state != FIP_ST_VNMP_UP) - return -EINVAL; + goto drop; if (ntoh24(fh->fh_d_id) == FC_FID_FLOGI) - return -EINVAL; + goto drop; } else { if (fip->state != FIP_ST_ENABLED) return 0; From f3ab0500e950d8cf088011f3ec919fcdbf7679cc Mon Sep 17 00:00:00 2001 From: Jim Gill Date: Thu, 2 Aug 2018 14:13:30 -0700 Subject: [PATCH 337/392] scsi: vmw_pvscsi: Return DID_RESET for status SAM_STAT_COMMAND_TERMINATED [ Upstream commit e95153b64d03c2b6e8d62e51bdcc33fcad6e0856 ] Commands that are reset are returned with status SAM_STAT_COMMAND_TERMINATED. PVSCSI currently returns DID_OK | SAM_STAT_COMMAND_TERMINATED which fails the command. Instead, set hostbyte to DID_RESET to allow upper layers to retry. Tested by copying a large file between two pvscsi disks on same adapter while performing a bus reset at 1-second intervals. Before fix, commands sometimes fail with DID_OK. After fix, commands observed to fail with DID_RESET. Signed-off-by: Jim Gill Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/vmw_pvscsi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 1a7154249e23..d5dd70049f81 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -567,9 +567,14 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, (btstat == BTSTAT_SUCCESS || btstat == BTSTAT_LINKED_COMMAND_COMPLETED || btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) { - cmd->result = (DID_OK << 16) | sdstat; - if (sdstat == SAM_STAT_CHECK_CONDITION && cmd->sense_buffer) - cmd->result |= (DRIVER_SENSE << 24); + if (sdstat == SAM_STAT_COMMAND_TERMINATED) { + cmd->result = (DID_RESET << 16); + } else { + cmd->result = (DID_OK << 16) | sdstat; + if (sdstat == SAM_STAT_CHECK_CONDITION && + cmd->sense_buffer) + cmd->result |= (DRIVER_SENSE << 24); + } } else switch (btstat) { case BTSTAT_SUCCESS: From 4c41a07aeead2a0808b245f36ecc8db9af7cd6a8 Mon Sep 17 00:00:00 2001 From: "jie@chenjie6@huwei.com" Date: Fri, 10 Aug 2018 17:23:06 -0700 Subject: [PATCH 338/392] mm/memory.c: check return value of ioremap_prot [ Upstream commit 24eee1e4c47977bdfb71d6f15f6011e7b6188d04 ] ioremap_prot() can return NULL which could lead to an oops. Link: http://lkml.kernel.org/r/1533195441-58594-1-git-send-email-chenjie6@huawei.com Signed-off-by: chen jie Reviewed-by: Andrew Morton Cc: Li Zefan Cc: chenjie Cc: Yang Shi Cc: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/memory.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/memory.c b/mm/memory.c index 0c4f5e36b155..003966808b3a 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3522,6 +3522,9 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, return -EINVAL; maddr = ioremap_prot(phys_addr, PAGE_ALIGN(len + offset), prot); + if (!maddr) + return -ENOMEM; + if (write) memcpy_toio(maddr + offset, buf, len); else From 8e46b7744059f62258fe07574e22070371b09071 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 19 Jul 2018 10:49:51 -0400 Subject: [PATCH 339/392] btrfs: don't leak ret from do_chunk_alloc commit 4559b0a71749c442d34f7cfb9e72c9e58db83948 upstream. If we're trying to make a data reservation and we have to allocate a data chunk we could leak ret == 1, as do_chunk_alloc() will return 1 if it allocated a chunk. Since the end of the function is the success path just return 0. CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Josef Bacik Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/extent-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 3f5fc150c2b7..b2937b645b62 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4281,7 +4281,7 @@ static int flush_space(struct btrfs_root *root, break; } - return ret; + return 0; } static inline u64 From ef2d2e24f2123445a4bef1f604499b0bf80057c8 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Mon, 16 Jul 2018 10:38:57 +0200 Subject: [PATCH 340/392] s390/kvm: fix deadlock when killed by oom commit 306d6c49ac9ded11114cb53b0925da52f2c2ada1 upstream. When the oom killer kills a userspace process in the page fault handler while in guest context, the fault handler fails to release the mm_sem if the FAULT_FLAG_RETRY_NOWAIT option is set. This leads to a deadlock when tearing down the mm when the process terminates. This bug can only happen when pfault is enabled, so only KVM clients are affected. The problem arises in the rare cases in which handle_mm_fault does not release the mm_sem. This patch fixes the issue by manually releasing the mm_sem when needed. Fixes: 24eb3a824c4f3 ("KVM: s390: Add FAULT_FLAG_RETRY_NOWAIT for guest fault") Cc: # 3.15+ Signed-off-by: Claudio Imbrenda Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/mm/fault.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index fbe8f2cf9245..eecd61bdc0d9 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -494,6 +494,8 @@ static inline int do_exception(struct pt_regs *regs, int access) /* No reason to continue if interrupted by SIGKILL. */ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) { fault = VM_FAULT_SIGNAL; + if (flags & FAULT_FLAG_RETRY_NOWAIT) + goto out_up; goto out; } if (unlikely(fault & VM_FAULT_ERROR)) From 1f9e5416abb6e0dd67761c846440148307002c85 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Sun, 29 Jul 2018 17:13:42 -0400 Subject: [PATCH 341/392] ext4: reset error code in ext4_find_entry in fallback commit f39b3f45dbcb0343822cce31ea7636ad66e60bc2 upstream. When ext4_find_entry() falls back to "searching the old fashioned way" due to a corrupt dx dir, it needs to reset the error code to NULL so that the nonstandard ERR_BAD_DX_DIR code isn't returned to userspace. https://bugzilla.kernel.org/show_bug.cgi?id=199947 Reported-by: Anatoly Trosinenko Reviewed-by: Andreas Dilger Signed-off-by: Eric Sandeen Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/namei.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 7c023859ba04..3217ca0e8dd4 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1242,6 +1242,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, return bh; dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, " "falling back\n")); + ret = NULL; } nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); if (!nblocks) { From 872f590e7a1883942c1ac6c78aa4a2dd01427b3a Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Wed, 15 Aug 2018 12:51:21 -0700 Subject: [PATCH 342/392] arm64: mm: check for upper PAGE_SHIFT bits in pfn_valid() commit 5ad356eabc47d26a92140a0c4b20eba471c10de3 upstream. ARM64's pfn_valid() shifts away the upper PAGE_SHIFT bits of the input before seeing if the PFN is valid. This leads to false positives when some of the upper bits are set, but the lower bits match a valid PFN. For example, the following userspace code looks up a bogus entry in /proc/kpageflags: int pagemap = open("/proc/self/pagemap", O_RDONLY); int pageflags = open("/proc/kpageflags", O_RDONLY); uint64_t pfn, val; lseek64(pagemap, [...], SEEK_SET); read(pagemap, &pfn, sizeof(pfn)); if (pfn & (1UL << 63)) { /* valid PFN */ pfn &= ((1UL << 55) - 1); /* clear flag bits */ pfn |= (1UL << 55); lseek64(pageflags, pfn * sizeof(uint64_t), SEEK_SET); read(pageflags, &val, sizeof(val)); } On ARM64 this causes the userspace process to crash with SIGSEGV rather than reading (1 << KPF_NOPAGE). kpageflags_read() treats the offset as valid, and stable_page_flags() will try to access an address between the user and kernel address ranges. Fixes: c1cc1552616d ("arm64: MMU initialisation") Cc: stable@vger.kernel.org Signed-off-by: Greg Hackmann Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/init.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index ed8affdf8f58..2ab1f8f22690 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -116,7 +116,11 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max) #ifdef CONFIG_HAVE_ARCH_PFN_VALID int pfn_valid(unsigned long pfn) { - return memblock_is_memory(pfn << PAGE_SHIFT); + phys_addr_t addr = pfn << PAGE_SHIFT; + + if ((addr >> PAGE_SHIFT) != pfn) + return 0; + return memblock_is_memory(addr); } EXPORT_SYMBOL(pfn_valid); #endif From 107c387a938558013533d7d82e425db67234f21c Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Mon, 13 Aug 2018 11:43:51 +0100 Subject: [PATCH 343/392] KVM: arm/arm64: Skip updating PTE entry if no change commit 976d34e2dab10ece5ea8fe7090b7692913f89084 upstream. When there is contention on faulting in a particular page table entry at stage 2, the break-before-make requirement of the architecture can lead to additional refaulting due to TLB invalidation. Avoid this by skipping a page table update if the new value of the PTE matches the previous value. Cc: stable@vger.kernel.org Fixes: d5d8184d35c9 ("KVM: ARM: Memory virtualization setup") Reviewed-by: Suzuki Poulose Acked-by: Christoffer Dall Signed-off-by: Punit Agrawal Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm/kvm/mmu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 3ffbce7277f7..dc3ae24e9d3d 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -898,6 +898,10 @@ static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, /* Create 2nd stage page table mapping - Level 3 */ old_pte = *pte; if (pte_present(old_pte)) { + /* Skip page table update if there is no change */ + if (pte_val(old_pte) == pte_val(*new_pte)) + return 0; + kvm_set_pte(pte, __pte(0)); kvm_tlb_flush_vmid_ipa(kvm, addr); } else { From a030af4fee1ae2624325a1e7e38b451ebf151a86 Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Mon, 13 Aug 2018 11:43:50 +0100 Subject: [PATCH 344/392] KVM: arm/arm64: Skip updating PMD entry if no change commit 86658b819cd0a9aa584cd84453ed268a6f013770 upstream. Contention on updating a PMD entry by a large number of vcpus can lead to duplicate work when handling stage 2 page faults. As the page table update follows the break-before-make requirement of the architecture, it can lead to repeated refaults due to clearing the entry and flushing the tlbs. This problem is more likely when - * there are large number of vcpus * the mapping is large block mapping such as when using PMD hugepages (512MB) with 64k pages. Fix this by skipping the page table update if there is no change in the entry being updated. Cc: stable@vger.kernel.org Fixes: ad361f093c1e ("KVM: ARM: Support hugetlbfs backed huge pages") Reviewed-by: Suzuki Poulose Acked-by: Christoffer Dall Signed-off-by: Punit Agrawal Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm/kvm/mmu.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index dc3ae24e9d3d..e506389d02fb 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -841,19 +841,35 @@ static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache pmd = stage2_get_pmd(kvm, cache, addr); VM_BUG_ON(!pmd); - /* - * Mapping in huge pages should only happen through a fault. If a - * page is merged into a transparent huge page, the individual - * subpages of that huge page should be unmapped through MMU - * notifiers before we get here. - * - * Merging of CompoundPages is not supported; they should become - * splitting first, unmapped, merged, and mapped back in on-demand. - */ - VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd)); - old_pmd = *pmd; if (pmd_present(old_pmd)) { + /* + * Multiple vcpus faulting on the same PMD entry, can + * lead to them sequentially updating the PMD with the + * same value. Following the break-before-make + * (pmd_clear() followed by tlb_flush()) process can + * hinder forward progress due to refaults generated + * on missing translations. + * + * Skip updating the page table if the entry is + * unchanged. + */ + if (pmd_val(old_pmd) == pmd_val(*new_pmd)) + return 0; + + /* + * Mapping in huge pages should only happen through a + * fault. If a page is merged into a transparent huge + * page, the individual subpages of that huge page + * should be unmapped through MMU notifiers before we + * get here. + * + * Merging of CompoundPages is not supported; they + * should become splitting first, unmapped, merged, + * and mapped back in on-demand. + */ + VM_BUG_ON(pmd_pfn(old_pmd) != pmd_pfn(*new_pmd)); + pmd_clear(pmd); kvm_tlb_flush_vmid_ipa(kvm, addr); } else { From 91196d94bdd3f2b434f9ef2a07ddfb551faa32e1 Mon Sep 17 00:00:00 2001 From: Rian Hunter Date: Sun, 19 Aug 2018 16:08:53 -0700 Subject: [PATCH 345/392] x86/process: Re-export start_thread() commit dc76803e57cc86589c4efcb5362918f9b0c0436f upstream. The consolidation of the start_thread() functions removed the export unintentionally. This breaks binfmt handlers built as a module. Add it back. Fixes: e634d8fc792c ("x86-64: merge the standard and compat start_thread() functions") Signed-off-by: Rian Hunter Signed-off-by: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Vitaly Kuznetsov Cc: Joerg Roedel Cc: Dmitry Safonov Cc: Josh Poimboeuf Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20180819230854.7275-1-rian@alum.mit.edu Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/process_64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index f547f866e86c..ba48e77c8e9e 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -438,6 +438,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) return prev_p; } +EXPORT_SYMBOL_GPL(start_thread); void set_personality_64bit(void) { From 9b39c90f1c2bc7bca594abd10715a4ffe2b16b2c Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Tue, 17 Jul 2018 19:00:33 +0300 Subject: [PATCH 346/392] fuse: Don't access pipe->buffers without pipe_lock() commit a2477b0e67c52f4364a47c3ad70902bc2a61bd4c upstream. fuse_dev_splice_write() reads pipe->buffers to determine the size of 'bufs' array before taking the pipe_lock(). This is not safe as another thread might change the 'pipe->buffers' between the allocation and taking the pipe_lock(). So we end up with too small 'bufs' array. Move the bufs allocations inside pipe_lock()/pipe_unlock() to fix this. Fixes: dd3bb14f44a6 ("fuse: support splice() writing to fuse device") Signed-off-by: Andrey Ryabinin Cc: # v2.6.35 Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/dev.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index f2bbb8513360..0834f5640875 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1913,11 +1913,14 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, if (!fc) return -EPERM; + pipe_lock(pipe); + bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL); - if (!bufs) + if (!bufs) { + pipe_unlock(pipe); return -ENOMEM; + } - pipe_lock(pipe); nbuf = 0; rem = 0; for (idx = 0; idx < pipe->nrbufs && rem < len; idx++) From e0dd67c762f650aae847260ddda8ffcaf15c477d Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 19 Jul 2018 15:49:39 +0300 Subject: [PATCH 347/392] fuse: Add missed unlock_page() to fuse_readpages_fill() commit 109728ccc5933151c68d1106e4065478a487a323 upstream. The above error path returns with page unlocked, so this place seems also to behave the same. Fixes: f8dbdf81821b ("fuse: rework fuse_readpages()") Signed-off-by: Kirill Tkhai Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 1f8cca580f50..24cceccb2140 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -910,6 +910,7 @@ static int fuse_readpages_fill(void *_data, struct page *page) } if (WARN_ON(req->num_pages >= req->max_pages)) { + unlock_page(page); fuse_put_request(fc, req); return -EIO; } From 8f02d4bb5a8a9ba242c31a7f44cf9958882599ba Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 3 Jun 2018 16:40:55 +0200 Subject: [PATCH 348/392] udl-kms: change down_interruptible to down commit 8456b99c16d193c4c3b7df305cf431e027f0189c upstream. If we leave urbs around, it causes not only leak, but also memory corruption. This patch fixes the function udl_free_urb_list, so that it always waits for all urbs that are in progress. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_main.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 33dbfb2c4748..2d7d7e0b2a23 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -141,18 +141,13 @@ static void udl_free_urb_list(struct drm_device *dev) struct list_head *node; struct urb_node *unode; struct urb *urb; - int ret; unsigned long flags; DRM_DEBUG("Waiting for completes and freeing all render urbs\n"); /* keep waiting and freeing, until we've got 'em all */ while (count--) { - - /* Getting interrupted means a leak, but ok at shutdown*/ - ret = down_interruptible(&udl->urbs.limit_sem); - if (ret) - break; + down(&udl->urbs.limit_sem); spin_lock_irqsave(&udl->urbs.lock, flags); From 953d8afde43fb6e7ec59e6e0628229e9dff5af1c Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 3 Jun 2018 16:40:56 +0200 Subject: [PATCH 349/392] udl-kms: handle allocation failure commit 542bb9788a1f485eb1a2229178f665d8ea166156 upstream. Allocations larger than PAGE_ALLOC_COSTLY_ORDER are unreliable and they may fail anytime. This patch fixes the udl kms driver so that when a large alloactions fails, it tries to do multiple smaller allocations. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_main.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 2d7d7e0b2a23..30bfeb1b2512 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -171,17 +171,22 @@ static void udl_free_urb_list(struct drm_device *dev) static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) { struct udl_device *udl = dev->dev_private; - int i = 0; struct urb *urb; struct urb_node *unode; char *buf; + size_t wanted_size = count * size; spin_lock_init(&udl->urbs.lock); +retry: udl->urbs.size = size; INIT_LIST_HEAD(&udl->urbs.list); - while (i < count) { + sema_init(&udl->urbs.limit_sem, 0); + udl->urbs.count = 0; + udl->urbs.available = 0; + + while (udl->urbs.count * size < wanted_size) { unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL); if (!unode) break; @@ -197,11 +202,16 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) } unode->urb = urb; - buf = usb_alloc_coherent(udl->udev, MAX_TRANSFER, GFP_KERNEL, + buf = usb_alloc_coherent(udl->udev, size, GFP_KERNEL, &urb->transfer_dma); if (!buf) { kfree(unode); usb_free_urb(urb); + if (size > PAGE_SIZE) { + size /= 2; + udl_free_urb_list(dev); + goto retry; + } break; } @@ -212,16 +222,14 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) list_add_tail(&unode->entry, &udl->urbs.list); - i++; + up(&udl->urbs.limit_sem); + udl->urbs.count++; + udl->urbs.available++; } - sema_init(&udl->urbs.limit_sem, i); - udl->urbs.count = i; - udl->urbs.available = i; - - DRM_DEBUG("allocated %d %d byte urbs\n", i, (int) size); + DRM_DEBUG("allocated %d %d byte urbs\n", udl->urbs.count, (int) size); - return i; + return udl->urbs.count; } struct urb *udl_get_urb(struct drm_device *dev) From aa6ba5e2fcc17c7125e4df835ec65d55603b8f95 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 3 Jun 2018 16:40:57 +0200 Subject: [PATCH 350/392] udl-kms: fix crash due to uninitialized memory commit 09a00abe3a9941c2715ca83eb88172cd2f54d8fd upstream. We must use kzalloc when allocating the fb_deferred_io structure. Otherwise, the field first_io is undefined and it causes a crash. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index ccb26652198b..06ca0100fb56 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -341,7 +341,7 @@ static int udl_fb_open(struct fb_info *info, int user) struct fb_deferred_io *fbdefio; - fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); + fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); if (fbdefio) { fbdefio->delay = DL_DEFIO_WRITE_DELAY; From 3aeaed1e802ece9347b57ce688c754320ae4ef72 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 26 Jul 2018 15:49:10 -0500 Subject: [PATCH 351/392] ASoC: sirf: Fix potential NULL pointer dereference commit ae1c696a480c67c45fb23b35162183f72c6be0e1 upstream. There is a potential execution path in which function platform_get_resource() returns NULL. If this happens, we will end up having a NULL pointer dereference. Fix this by replacing devm_ioremap with devm_ioremap_resource, which has the NULL check and the memory region request. This code was detected with the help of Coccinelle. Cc: stable@vger.kernel.org Fixes: 2bd8d1d5cf89 ("ASoC: sirf: Add audio usp interface driver") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/sirf/sirf-usp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c index 186dc7f33a55..cdb7416a91ff 100644 --- a/sound/soc/sirf/sirf-usp.c +++ b/sound/soc/sirf/sirf-usp.c @@ -367,10 +367,9 @@ static int sirf_usp_pcm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, usp); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap(&pdev->dev, mem_res->start, - resource_size(mem_res)); - if (base == NULL) - return -ENOMEM; + base = devm_ioremap_resource(&pdev->dev, mem_res); + if (IS_ERR(base)) + return PTR_ERR(base); usp->regmap = devm_regmap_init_mmio(&pdev->dev, base, &sirf_usp_regmap_config); if (IS_ERR(usp->regmap)) From 0fd19868d76345529583873235f7533cdc7623d7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 13 Jul 2018 17:55:15 +0300 Subject: [PATCH 352/392] pinctrl: freescale: off by one in imx1_pinconf_group_dbg_show() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 19da44cd33a3a6ff7c97fff0189999ff15b241e4 upstream. The info->groups[] array is allocated in imx1_pinctrl_parse_dt(). It has info->ngroups elements. Thus the > here should be >= to prevent reading one element beyond the end of the array. Cc: stable@vger.kernel.org Fixes: 30612cd90005 ("pinctrl: imx1 core driver") Signed-off-by: Dan Carpenter Reviewed-by: Uwe Kleine-König Acked-by: Dong Aisheng Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/freescale/pinctrl-imx1-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c index 5ac59fbb2440..d6115d3835ee 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c +++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c @@ -435,7 +435,7 @@ static void imx1_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, const char *name; int i, ret; - if (group > info->ngroups) + if (group >= info->ngroups) return; seq_puts(s, "\n"); From dc826c93cd8015370182b9362dea84250399a9eb Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 16 May 2018 09:37:25 +0200 Subject: [PATCH 353/392] s390/qdio: reset old sbal_state flags commit 64e03ff72623b8c2ea89ca3cb660094e019ed4ae upstream. When allocating a new AOB fails, handle_outbound() is still capable of transmitting the selected buffer (just without async completion). But if a previous transfer on this queue slot used async completion, its sbal_state flags field is still set to QDIO_OUTBUF_STATE_FLAG_PENDING. So when the upper layer driver sees this stale flag, it expects an async completion that never happens. Fix this by unconditionally clearing the flags field. Fixes: 104ea556ee7f ("qdio: support asynchronous delivery of storage blocks") Cc: #v3.2+ Signed-off-by: Julian Wiedmann Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/qdio.h | 1 - drivers/s390/cio/qdio_main.c | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 06f3034605a1..33894abf03df 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -271,7 +271,6 @@ struct qdio_outbuf_state { void *user; }; -#define QDIO_OUTBUF_STATE_FLAG_NONE 0x00 #define QDIO_OUTBUF_STATE_FLAG_PENDING 0x01 #define CHSC_AC1_INITIATE_INPUTQ 0x80 diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index fb7298920c8c..90f93c2be8cd 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -640,21 +640,20 @@ static inline unsigned long qdio_aob_for_buffer(struct qdio_output_q *q, unsigned long phys_aob = 0; if (!q->use_cq) - goto out; + return 0; if (!q->aobs[bufnr]) { struct qaob *aob = qdio_allocate_aob(); q->aobs[bufnr] = aob; } if (q->aobs[bufnr]) { - q->sbal_state[bufnr].flags = QDIO_OUTBUF_STATE_FLAG_NONE; q->sbal_state[bufnr].aob = q->aobs[bufnr]; q->aobs[bufnr]->user1 = (u64) q->sbal_state[bufnr].user; phys_aob = virt_to_phys(q->aobs[bufnr]); WARN_ON_ONCE(phys_aob & 0xFF); } -out: + q->sbal_state[bufnr].flags = 0; return phys_aob; } From be4f8c44a1c7045a313121ad4549b000c861efab Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Mon, 13 Aug 2018 11:26:46 +0200 Subject: [PATCH 354/392] s390/pci: fix out of bounds access during irq setup commit 866f3576a72b2233a76dffb80290f8086dc49e17 upstream. During interrupt setup we allocate interrupt vectors, walk the list of msi descriptors, and fill in the message data. Requesting more interrupts than supported on s390 can lead to an out of bounds access. When we restrict the number of interrupts we should also stop walking the msi list after all supported interrupts are handled. Cc: stable@vger.kernel.org Signed-off-by: Sebastian Ott Signed-off-by: Heiko Carstens Signed-off-by: Greg Kroah-Hartman --- arch/s390/pci/pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 944818617718..7926500e5169 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -397,6 +397,8 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) hwirq = 0; list_for_each_entry(msi, &pdev->msi_list, list) { rc = -EIO; + if (hwirq >= msi_vecs) + break; irq = irq_alloc_desc(0); /* Alloc irq on node 0 */ if (irq < 0) goto out_msi; From 7ab91fb4243859720792b7d3436dcd262ccc187a Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 28 Apr 2018 21:35:01 +0900 Subject: [PATCH 355/392] kprobes: Make list and blacklist root user read only commit f2a3ab36077222437b4826fc76111caa14562b7c upstream. Since the blacklist and list files on debugfs indicates a sensitive address information to reader, it should be restricted to the root user. Suggested-by: Thomas Richter Suggested-by: Ingo Molnar Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Anil S Keshavamurthy Cc: Arnd Bergmann Cc: David Howells Cc: David S . Miller Cc: Heiko Carstens Cc: Jon Medhurst Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tobin C . Harding Cc: Will Deacon Cc: acme@kernel.org Cc: akpm@linux-foundation.org Cc: brueckner@linux.vnet.ibm.com Cc: linux-arch@vger.kernel.org Cc: rostedt@goodmis.org Cc: schwidefsky@de.ibm.com Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/lkml/152491890171.9916.5183693615601334087.stgit@devbox Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/kprobes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 359d4de103b7..44cce4d45b82 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -2425,7 +2425,7 @@ static int __init debugfs_kprobe_init(void) if (!dir) return -ENOMEM; - file = debugfs_create_file("list", 0444, dir, NULL, + file = debugfs_create_file("list", 0400, dir, NULL, &debugfs_kprobes_operations); if (!file) goto error; @@ -2435,7 +2435,7 @@ static int __init debugfs_kprobe_init(void) if (!file) goto error; - file = debugfs_create_file("blacklist", 0444, dir, NULL, + file = debugfs_create_file("blacklist", 0400, dir, NULL, &debugfs_kprobe_blacklist_ops); if (!file) goto error; From 1d7acd2e136511d8d7e5a52e9fa8489502263962 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 15 May 2018 23:33:26 +0100 Subject: [PATCH 356/392] MIPS: Correct the 64-bit DSP accumulator register size commit f5958b4cf4fc38ed4583ab83fb7c4cd1ab05f47b upstream. Use the `unsigned long' rather than `__u32' type for DSP accumulator registers, like with the regular MIPS multiply/divide accumulator and general-purpose registers, as all are 64-bit in 64-bit implementations and using a 32-bit data type leads to contents truncation on context saving. Update `arch_ptrace' and `compat_arch_ptrace' accordingly, removing casts that are similarly not used with multiply/divide accumulator or general-purpose register accesses. Signed-off-by: Maciej W. Rozycki Signed-off-by: Paul Burton Fixes: e50c0a8fa60d ("Support the MIPS32 / MIPS64 DSP ASE.") Patchwork: https://patchwork.linux-mips.org/patch/19329/ Cc: Alexander Viro Cc: James Hogan Cc: Ralf Baechle Cc: linux-fsdevel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org # 2.6.15+ Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/processor.h | 2 +- arch/mips/kernel/ptrace.c | 2 +- arch/mips/kernel/ptrace32.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 578ece1e4a99..351a5a9e4f52 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -143,7 +143,7 @@ struct mips_fpu_struct { #define NUM_DSP_REGS 6 -typedef __u32 dspreg_t; +typedef unsigned long dspreg_t; struct mips_dsp_state { dspreg_t dspr[NUM_DSP_REGS]; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index c1bd750494c1..0b16f07ada9f 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -751,7 +751,7 @@ long arch_ptrace(struct task_struct *child, long request, goto out; } dregs = __get_dsp_regs(child); - tmp = (unsigned long) (dregs[addr - DSP_BASE]); + tmp = dregs[addr - DSP_BASE]; break; } case DSP_CONTROL: diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index d95117e71f69..286ec2d24d47 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -140,7 +140,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, goto out; } dregs = __get_dsp_regs(child); - tmp = (unsigned long) (dregs[addr - DSP_BASE]); + tmp = dregs[addr - DSP_BASE]; break; } case DSP_CONTROL: From a6abc93760dd07fcd29760b70e6e7520f22cb288 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 2 Aug 2018 10:51:40 -0700 Subject: [PATCH 357/392] scsi: sysfs: Introduce sysfs_{un,}break_active_protection() commit 2afc9166f79b8f6da5f347f48515215ceee4ae37 upstream. Introduce these two functions and export them such that the next patch can add calls to these functions from the SCSI core. Signed-off-by: Bart Van Assche Acked-by: Tejun Heo Acked-by: Greg Kroah-Hartman Cc: Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 44 +++++++++++++++++++++++++++++++++++++++++++ include/linux/sysfs.h | 14 ++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index e9ef59b3abb1..154a4a953887 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -356,6 +356,50 @@ int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, } EXPORT_SYMBOL_GPL(sysfs_chmod_file); +/** + * sysfs_break_active_protection - break "active" protection + * @kobj: The kernel object @attr is associated with. + * @attr: The attribute to break the "active" protection for. + * + * With sysfs, just like kernfs, deletion of an attribute is postponed until + * all active .show() and .store() callbacks have finished unless this function + * is called. Hence this function is useful in methods that implement self + * deletion. + */ +struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj, + const struct attribute *attr) +{ + struct kernfs_node *kn; + + kobject_get(kobj); + kn = kernfs_find_and_get(kobj->sd, attr->name); + if (kn) + kernfs_break_active_protection(kn); + return kn; +} +EXPORT_SYMBOL_GPL(sysfs_break_active_protection); + +/** + * sysfs_unbreak_active_protection - restore "active" protection + * @kn: Pointer returned by sysfs_break_active_protection(). + * + * Undo the effects of sysfs_break_active_protection(). Since this function + * calls kernfs_put() on the kernfs node that corresponds to the 'attr' + * argument passed to sysfs_break_active_protection() that attribute may have + * been removed between the sysfs_break_active_protection() and + * sysfs_unbreak_active_protection() calls, it is not safe to access @kn after + * this function has returned. + */ +void sysfs_unbreak_active_protection(struct kernfs_node *kn) +{ + struct kobject *kobj = kn->parent->priv; + + kernfs_unbreak_active_protection(kn); + kernfs_put(kn); + kobject_put(kobj); +} +EXPORT_SYMBOL_GPL(sysfs_unbreak_active_protection); + /** * sysfs_remove_file_ns - remove an object attribute with a custom ns tag * @kobj: object we're acting for diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 70ceb2a14a57..8e0c151cc07c 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -200,6 +200,9 @@ int __must_check sysfs_create_files(struct kobject *kobj, const struct attribute **attr); int __must_check sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, umode_t mode); +struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj, + const struct attribute *attr); +void sysfs_unbreak_active_protection(struct kernfs_node *kn); void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, const void *ns); bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr); @@ -299,6 +302,17 @@ static inline int sysfs_chmod_file(struct kobject *kobj, return 0; } +static inline struct kernfs_node * +sysfs_break_active_protection(struct kobject *kobj, + const struct attribute *attr) +{ + return NULL; +} + +static inline void sysfs_unbreak_active_protection(struct kernfs_node *kn) +{ +} + static inline void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, const void *ns) From 86c0a645ffd20ee8e6063f1e9dfba07d35fded5e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 2 Aug 2018 10:51:41 -0700 Subject: [PATCH 358/392] scsi: core: Avoid that SCSI device removal through sysfs triggers a deadlock commit 0ee223b2e1f67cb2de9c0e3247c510d846e74d63 upstream. A long time ago the unfortunate decision was taken to add a self-deletion attribute to the sysfs SCSI device directory. That decision was unfortunate because self-deletion is really tricky. We can't drop that attribute because widely used user space software depends on it, namely the rescan-scsi-bus.sh script. Hence this patch that avoids that writing into that attribute triggers a deadlock. See also commit 7973cbd9fbd9 ("[PATCH] add sysfs attributes to scan and delete scsi_devices"). This patch avoids that self-removal triggers the following deadlock: ====================================================== WARNING: possible circular locking dependency detected 4.18.0-rc2-dbg+ #5 Not tainted ------------------------------------------------------ modprobe/6539 is trying to acquire lock: 000000008323c4cd (kn->count#202){++++}, at: kernfs_remove_by_name_ns+0x45/0x90 but task is already holding lock: 00000000a6ec2c69 (&shost->scan_mutex){+.+.}, at: scsi_remove_host+0x21/0x150 [scsi_mod] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&shost->scan_mutex){+.+.}: __mutex_lock+0xfe/0xc70 mutex_lock_nested+0x1b/0x20 scsi_remove_device+0x26/0x40 [scsi_mod] sdev_store_delete+0x27/0x30 [scsi_mod] dev_attr_store+0x3e/0x50 sysfs_kf_write+0x87/0xa0 kernfs_fop_write+0x190/0x230 __vfs_write+0xd2/0x3b0 vfs_write+0x101/0x270 ksys_write+0xab/0x120 __x64_sys_write+0x43/0x50 do_syscall_64+0x77/0x230 entry_SYSCALL_64_after_hwframe+0x49/0xbe -> #0 (kn->count#202){++++}: lock_acquire+0xd2/0x260 __kernfs_remove+0x424/0x4a0 kernfs_remove_by_name_ns+0x45/0x90 remove_files.isra.1+0x3a/0x90 sysfs_remove_group+0x5c/0xc0 sysfs_remove_groups+0x39/0x60 device_remove_attrs+0x82/0xb0 device_del+0x251/0x580 __scsi_remove_device+0x19f/0x1d0 [scsi_mod] scsi_forget_host+0x37/0xb0 [scsi_mod] scsi_remove_host+0x9b/0x150 [scsi_mod] sdebug_driver_remove+0x4b/0x150 [scsi_debug] device_release_driver_internal+0x241/0x360 device_release_driver+0x12/0x20 bus_remove_device+0x1bc/0x290 device_del+0x259/0x580 device_unregister+0x1a/0x70 sdebug_remove_adapter+0x8b/0xf0 [scsi_debug] scsi_debug_exit+0x76/0xe8 [scsi_debug] __x64_sys_delete_module+0x1c1/0x280 do_syscall_64+0x77/0x230 entry_SYSCALL_64_after_hwframe+0x49/0xbe other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&shost->scan_mutex); lock(kn->count#202); lock(&shost->scan_mutex); lock(kn->count#202); *** DEADLOCK *** 2 locks held by modprobe/6539: #0: 00000000efaf9298 (&dev->mutex){....}, at: device_release_driver_internal+0x68/0x360 #1: 00000000a6ec2c69 (&shost->scan_mutex){+.+.}, at: scsi_remove_host+0x21/0x150 [scsi_mod] stack backtrace: CPU: 10 PID: 6539 Comm: modprobe Not tainted 4.18.0-rc2-dbg+ #5 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014 Call Trace: dump_stack+0xa4/0xf5 print_circular_bug.isra.34+0x213/0x221 __lock_acquire+0x1a7e/0x1b50 lock_acquire+0xd2/0x260 __kernfs_remove+0x424/0x4a0 kernfs_remove_by_name_ns+0x45/0x90 remove_files.isra.1+0x3a/0x90 sysfs_remove_group+0x5c/0xc0 sysfs_remove_groups+0x39/0x60 device_remove_attrs+0x82/0xb0 device_del+0x251/0x580 __scsi_remove_device+0x19f/0x1d0 [scsi_mod] scsi_forget_host+0x37/0xb0 [scsi_mod] scsi_remove_host+0x9b/0x150 [scsi_mod] sdebug_driver_remove+0x4b/0x150 [scsi_debug] device_release_driver_internal+0x241/0x360 device_release_driver+0x12/0x20 bus_remove_device+0x1bc/0x290 device_del+0x259/0x580 device_unregister+0x1a/0x70 sdebug_remove_adapter+0x8b/0xf0 [scsi_debug] scsi_debug_exit+0x76/0xe8 [scsi_debug] __x64_sys_delete_module+0x1c1/0x280 do_syscall_64+0x77/0x230 entry_SYSCALL_64_after_hwframe+0x49/0xbe See also https://www.mail-archive.com/linux-scsi@vger.kernel.org/msg54525.html. Fixes: ac0ece9174ac ("scsi: use device_remove_file_self() instead of device_schedule_callback()") Signed-off-by: Bart Van Assche Cc: Greg Kroah-Hartman Acked-by: Tejun Heo Cc: Johannes Thumshirn Cc: Signed-off-by: Greg Kroah-Hartman Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_sysfs.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 9bfc6835ff2f..a1d68419e312 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -676,8 +676,24 @@ static ssize_t sdev_store_delete(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - if (device_remove_file_self(dev, attr)) - scsi_remove_device(to_scsi_device(dev)); + struct kernfs_node *kn; + + kn = sysfs_break_active_protection(&dev->kobj, &attr->attr); + WARN_ON_ONCE(!kn); + /* + * Concurrent writes into the "delete" sysfs attribute may trigger + * concurrent calls to device_remove_file() and scsi_remove_device(). + * device_remove_file() handles concurrent removal calls by + * serializing these and by ignoring the second and later removal + * attempts. Concurrent calls of scsi_remove_device() are + * serialized. The second and later calls of scsi_remove_device() are + * ignored because the first call of that function changes the device + * state into SDEV_DEL. + */ + device_remove_file(dev, attr); + scsi_remove_device(to_scsi_device(dev)); + if (kn) + sysfs_unbreak_active_protection(kn); return count; }; static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete); From 2f294385874e8e152f357531aa177a19560c8a64 Mon Sep 17 00:00:00 2001 From: Scott Bauer Date: Thu, 26 Apr 2018 11:51:08 -0600 Subject: [PATCH 359/392] cdrom: Fix info leak/OOB read in cdrom_ioctl_drive_status commit 8f3fafc9c2f0ece10832c25f7ffcb07c97a32ad4 upstream. Like d88b6d04: "cdrom: information leak in cdrom_ioctl_media_changed()" There is another cast from unsigned long to int which causes a bounds check to fail with specially crafted input. The value is then used as an index in the slot array in cdrom_slot_status(). Signed-off-by: Scott Bauer Signed-off-by: Scott Bauer Cc: stable@vger.kernel.org Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/cdrom/cdrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 998991a365b8..81fb29741dc1 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2525,7 +2525,7 @@ static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi, if (!CDROM_CAN(CDC_SELECT_DISC) || (arg == CDSL_CURRENT || arg == CDSL_NONE)) return cdi->ops->drive_status(cdi, CDSL_CURRENT); - if (((int)arg >= cdi->capacity)) + if (arg >= cdi->capacity) return -EINVAL; return cdrom_slot_status(cdi, arg); } From ba6984fc0162f24a510ebc34e881b546b69c553b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 5 Sep 2018 09:16:24 +0200 Subject: [PATCH 360/392] Linux 3.18.121 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2ba32f17a470..9a58c977c946 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 18 -SUBLEVEL = 120 +SUBLEVEL = 121 EXTRAVERSION = NAME = Diseased Newt From 569bdeda7ecf6f64b8426539b1fb00f4d8eef90c Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sat, 8 Sep 2018 10:27:25 -0700 Subject: [PATCH 361/392] ALSA: rawmidi: Undo my 3.18.117 resolution This reverts commit bfa30d8adcee ("ALSA: rawmidi: Change resized buffers atomically") in favor of commit b68f2a9039de ("ANDROID: sound: rawmidi: Hold lock around realloc"). This matches Qualcomm's resolution in 4.4: https://source.codeaurora.org/quic/la/kernel/msm-4.4/commit/?id=facb909e66d37224f564750e8ebc693b91934ec6 Signed-off-by: Nathan Chancellor --- include/sound/rawmidi.h | 1 + sound/core/rawmidi.c | 56 ++++++++++++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 5bd2bfbf6dd1..0afad5cd6253 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -77,6 +77,7 @@ struct snd_rawmidi_runtime { size_t xruns; /* over/underruns counter */ /* misc */ spinlock_t lock; + struct mutex realloc_mutex; wait_queue_head_t sleep; /* event handler (new bytes, input only) */ void (*event)(struct snd_rawmidi_substream *substream); diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 57e4ab148fe3..5c21625ae198 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -115,6 +115,7 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) return -ENOMEM; runtime->substream = substream; spin_lock_init(&runtime->lock); + mutex_init(&runtime->realloc_mutex); init_waitqueue_head(&runtime->sleep); INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work); runtime->event = NULL; @@ -645,9 +646,11 @@ static int snd_rawmidi_info_select_user(struct snd_card *card, int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params * params) { - char *newbuf, *oldbuf; + char *newbuf; + char *oldbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; - + unsigned long flags; + if (substream->append && substream->use_count > 1) return -EBUSY; snd_rawmidi_drain_output(substream); @@ -658,17 +661,22 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = kmalloc(params->buffer_size, GFP_KERNEL); - if (!newbuf) + mutex_lock(&runtime->realloc_mutex); + newbuf = __krealloc(runtime->buffer, params->buffer_size, + GFP_KERNEL); + if (!newbuf) { + mutex_unlock(&runtime->realloc_mutex); return -ENOMEM; - spin_lock_irq(&runtime->lock); + } + spin_lock_irqsave(&runtime->lock, flags); oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; runtime->avail = runtime->buffer_size; - runtime->appl_ptr = runtime->hw_ptr = 0; - spin_unlock_irq(&runtime->lock); - kfree(oldbuf); + spin_unlock_irqrestore(&runtime->lock, flags); + if (oldbuf != newbuf) + kfree(oldbuf); + mutex_unlock(&runtime->realloc_mutex); } runtime->avail_min = params->avail_min; substream->active_sensing = !params->no_active_sensing; @@ -679,8 +687,10 @@ EXPORT_SYMBOL(snd_rawmidi_output_params); int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params * params) { - char *newbuf, *oldbuf; + char *newbuf; + char *oldbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long flags; snd_rawmidi_drain_input(substream); if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) { @@ -690,16 +700,21 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = kmalloc(params->buffer_size, GFP_KERNEL); - if (!newbuf) + mutex_lock(&runtime->realloc_mutex); + newbuf = __krealloc(runtime->buffer, params->buffer_size, + GFP_KERNEL); + if (!newbuf) { + mutex_unlock(&runtime->realloc_mutex); return -ENOMEM; - spin_lock_irq(&runtime->lock); + } + spin_lock_irqsave(&runtime->lock, flags); oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; - runtime->appl_ptr = runtime->hw_ptr = 0; - spin_unlock_irq(&runtime->lock); - kfree(oldbuf); + spin_unlock_irqrestore(&runtime->lock, flags); + if (oldbuf != newbuf) + kfree(oldbuf); + mutex_unlock(&runtime->realloc_mutex); } runtime->avail_min = params->avail_min; return 0; @@ -971,6 +986,8 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, struct snd_rawmidi_runtime *runtime = substream->runtime; unsigned long appl_ptr; + if (userbuf) + mutex_lock(&runtime->realloc_mutex); spin_lock_irqsave(&runtime->lock, flags); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; @@ -991,6 +1008,7 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, spin_unlock_irqrestore(&runtime->lock, flags); if (copy_to_user(userbuf + result, runtime->buffer + appl_ptr, count1)) { + mutex_unlock(&runtime->realloc_mutex); return result > 0 ? result : -EFAULT; } spin_lock_irqsave(&runtime->lock, flags); @@ -999,6 +1017,8 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, count -= count1; } spin_unlock_irqrestore(&runtime->lock, flags); + if (userbuf) + mutex_unlock(&runtime->realloc_mutex); return result; } @@ -1263,10 +1283,14 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, return -EINVAL; result = 0; + if (userbuf) + mutex_lock(&runtime->realloc_mutex); spin_lock_irqsave(&runtime->lock, flags); if (substream->append) { if ((long)runtime->avail < count) { spin_unlock_irqrestore(&runtime->lock, flags); + if (userbuf) + mutex_unlock(&runtime->realloc_mutex); return -EAGAIN; } } @@ -1302,6 +1326,8 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, __end: count1 = runtime->avail < runtime->buffer_size; spin_unlock_irqrestore(&runtime->lock, flags); + if (userbuf) + mutex_unlock(&runtime->realloc_mutex); if (count1) snd_rawmidi_output_trigger(substream, 1); return result; From fec7d721a09b917f6fa8b923a28fbac97c1217ba Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 10 Aug 2018 11:13:52 +0200 Subject: [PATCH 362/392] spi: davinci: fix a NULL pointer dereference commit 563a53f3906a6b43692498e5b3ae891fac93a4af upstream. On non-OF systems spi->controlled_data may be NULL. This causes a NULL pointer derefence on dm365-evm. Signed-off-by: Bartosz Golaszewski Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-davinci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 63700ab7bd9f..1107a5d5a256 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -230,7 +230,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) } /* program delay transfers if tx_delay is non zero */ - if (spicfg->wdelay) + if (spicfg && spicfg->wdelay) spidat1 |= SPIDAT1_WDEL; /* From b3f3454eb475f6e7f53bf5029cde593ca267c3a0 Mon Sep 17 00:00:00 2001 From: Hari Bathini Date: Tue, 7 Aug 2018 02:12:45 +0530 Subject: [PATCH 363/392] powerpc/fadump: handle crash memory ranges array index overflow commit 1bd6a1c4b80a28d975287630644e6b47d0f977a5 upstream. Crash memory ranges is an array of memory ranges of the crashing kernel to be exported as a dump via /proc/vmcore file. The size of the array is set based on INIT_MEMBLOCK_REGIONS, which works alright in most cases where memblock memory regions count is less than INIT_MEMBLOCK_REGIONS value. But this count can grow beyond INIT_MEMBLOCK_REGIONS value since commit 142b45a72e22 ("memblock: Add array resizing support"). On large memory systems with a few DLPAR operations, the memblock memory regions count could be larger than INIT_MEMBLOCK_REGIONS value. On such systems, registering fadump results in crash or other system failures like below: task: c00007f39a290010 ti: c00000000b738000 task.ti: c00000000b738000 NIP: c000000000047df4 LR: c0000000000f9e58 CTR: c00000000010f180 REGS: c00000000b73b570 TRAP: 0300 Tainted: G L X (4.4.140+) MSR: 8000000000009033 CR: 22004484 XER: 20000000 CFAR: c000000000008500 DAR: 000007a450000000 DSISR: 40000000 SOFTE: 0 ... NIP [c000000000047df4] smp_send_reschedule+0x24/0x80 LR [c0000000000f9e58] resched_curr+0x138/0x160 Call Trace: resched_curr+0x138/0x160 (unreliable) check_preempt_curr+0xc8/0xf0 ttwu_do_wakeup+0x38/0x150 try_to_wake_up+0x224/0x4d0 __wake_up_common+0x94/0x100 ep_poll_callback+0xac/0x1c0 __wake_up_common+0x94/0x100 __wake_up_sync_key+0x70/0xa0 sock_def_readable+0x58/0xa0 unix_stream_sendmsg+0x2dc/0x4c0 sock_sendmsg+0x68/0xa0 ___sys_sendmsg+0x2cc/0x2e0 __sys_sendmsg+0x5c/0xc0 SyS_socketcall+0x36c/0x3f0 system_call+0x3c/0x100 as array index overflow is not checked for while setting up crash memory ranges causing memory corruption. To resolve this issue, dynamically allocate memory for crash memory ranges and resize it incrementally, in units of pagesize, on hitting array size limit. Fixes: 2df173d9e85d ("fadump: Initialize elfcore header and add PT_LOAD program headers.") Cc: stable@vger.kernel.org # v3.4+ Signed-off-by: Hari Bathini Reviewed-by: Mahesh Salgaonkar [mpe: Just use PAGE_SIZE directly, fixup variable placement] Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/fadump.h | 3 - arch/powerpc/kernel/fadump.c | 92 ++++++++++++++++++++++++++----- 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h index 493e72f64b35..5768ec3c1781 100644 --- a/arch/powerpc/include/asm/fadump.h +++ b/arch/powerpc/include/asm/fadump.h @@ -194,9 +194,6 @@ struct fadump_crash_info_header { struct cpumask cpu_online_mask; }; -/* Crash memory ranges */ -#define INIT_CRASHMEM_RANGES (INIT_MEMBLOCK_REGIONS + 2) - struct fad_crash_memory_ranges { unsigned long long base; unsigned long long size; diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 791d4c3329c3..c3c835290131 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -48,8 +49,10 @@ static struct fadump_mem_struct fdm; static const struct fadump_mem_struct *fdm_active; static DEFINE_MUTEX(fadump_mutex); -struct fad_crash_memory_ranges crash_memory_ranges[INIT_CRASHMEM_RANGES]; +struct fad_crash_memory_ranges *crash_memory_ranges; +int crash_memory_ranges_size; int crash_mem_ranges; +int max_crash_mem_ranges; /* Scan the Firmware Assisted dump configuration details. */ int __init early_init_dt_scan_fw_dump(unsigned long node, @@ -726,38 +729,88 @@ static int __init process_fadump(const struct fadump_mem_struct *fdm_active) return 0; } -static inline void fadump_add_crash_memory(unsigned long long base, - unsigned long long end) +static void free_crash_memory_ranges(void) +{ + kfree(crash_memory_ranges); + crash_memory_ranges = NULL; + crash_memory_ranges_size = 0; + max_crash_mem_ranges = 0; +} + +/* + * Allocate or reallocate crash memory ranges array in incremental units + * of PAGE_SIZE. + */ +static int allocate_crash_memory_ranges(void) +{ + struct fad_crash_memory_ranges *new_array; + u64 new_size; + + new_size = crash_memory_ranges_size + PAGE_SIZE; + pr_debug("Allocating %llu bytes of memory for crash memory ranges\n", + new_size); + + new_array = krealloc(crash_memory_ranges, new_size, GFP_KERNEL); + if (new_array == NULL) { + pr_err("Insufficient memory for setting up crash memory ranges\n"); + free_crash_memory_ranges(); + return -ENOMEM; + } + + crash_memory_ranges = new_array; + crash_memory_ranges_size = new_size; + max_crash_mem_ranges = (new_size / + sizeof(struct fad_crash_memory_ranges)); + return 0; +} + +static inline int fadump_add_crash_memory(unsigned long long base, + unsigned long long end) { if (base == end) - return; + return 0; + + if (crash_mem_ranges == max_crash_mem_ranges) { + int ret; + + ret = allocate_crash_memory_ranges(); + if (ret) + return ret; + } pr_debug("crash_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n", crash_mem_ranges, base, end - 1, (end - base)); crash_memory_ranges[crash_mem_ranges].base = base; crash_memory_ranges[crash_mem_ranges].size = end - base; crash_mem_ranges++; + return 0; } -static void fadump_exclude_reserved_area(unsigned long long start, +static int fadump_exclude_reserved_area(unsigned long long start, unsigned long long end) { unsigned long long ra_start, ra_end; + int ret = 0; ra_start = fw_dump.reserve_dump_area_start; ra_end = ra_start + fw_dump.reserve_dump_area_size; if ((ra_start < end) && (ra_end > start)) { if ((start < ra_start) && (end > ra_end)) { - fadump_add_crash_memory(start, ra_start); - fadump_add_crash_memory(ra_end, end); + ret = fadump_add_crash_memory(start, ra_start); + if (ret) + return ret; + + ret = fadump_add_crash_memory(ra_end, end); } else if (start < ra_start) { - fadump_add_crash_memory(start, ra_start); + ret = fadump_add_crash_memory(start, ra_start); } else if (ra_end < end) { - fadump_add_crash_memory(ra_end, end); + ret = fadump_add_crash_memory(ra_end, end); } } else - fadump_add_crash_memory(start, end); + ret = fadump_add_crash_memory(start, end); + + return ret; } static int fadump_init_elfcore_header(char *bufp) @@ -793,10 +846,11 @@ static int fadump_init_elfcore_header(char *bufp) * Traverse through memblock structure and setup crash memory ranges. These * ranges will be used create PT_LOAD program headers in elfcore header. */ -static void fadump_setup_crash_memory_ranges(void) +static int fadump_setup_crash_memory_ranges(void) { struct memblock_region *reg; unsigned long long start, end; + int ret; pr_debug("Setup crash memory ranges.\n"); crash_mem_ranges = 0; @@ -807,7 +861,9 @@ static void fadump_setup_crash_memory_ranges(void) * specified during fadump registration. We need to create a separate * program header for this chunk with the correct offset. */ - fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size); + ret = fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size); + if (ret) + return ret; for_each_memblock(memory, reg) { start = (unsigned long long)reg->base; @@ -816,8 +872,12 @@ static void fadump_setup_crash_memory_ranges(void) start = fw_dump.boot_memory_size; /* add this range excluding the reserved dump area. */ - fadump_exclude_reserved_area(start, end); + ret = fadump_exclude_reserved_area(start, end); + if (ret) + return ret; } + + return 0; } /* @@ -941,6 +1001,7 @@ static void register_fadump(void) { unsigned long addr; void *vaddr; + int ret; /* * If no memory is reserved then we can not register for firmware- @@ -949,7 +1010,9 @@ static void register_fadump(void) if (!fw_dump.reserve_dump_area_size) return; - fadump_setup_crash_memory_ranges(); + ret = fadump_setup_crash_memory_ranges(); + if (ret) + return ret; addr = be64_to_cpu(fdm.rmr_region.destination_address) + be64_to_cpu(fdm.rmr_region.source_len); /* Initialize fadump crash info header. */ @@ -1028,6 +1091,7 @@ void fadump_cleanup(void) } else if (fw_dump.dump_registered) { /* Un-register Firmware-assisted dump if it was registered. */ fadump_unregister_dump(&fdm); + free_crash_memory_ranges(); } } From 43a2089a1353159c24eaad3f8925c4710b9e7c16 Mon Sep 17 00:00:00 2001 From: Mahesh Salgaonkar Date: Tue, 7 Aug 2018 19:46:46 +0530 Subject: [PATCH 364/392] powerpc/pseries: Fix endianness while restoring of r3 in MCE handler. commit cd813e1cd7122f2c261dce5b54d1e0c97f80e1a5 upstream. During Machine Check interrupt on pseries platform, register r3 points RTAS extended event log passed by hypervisor. Since hypervisor uses r3 to pass pointer to rtas log, it stores the original r3 value at the start of the memory (first 8 bytes) pointed by r3. Since hypervisor stores this info and rtas log is in BE format, linux should make sure to restore r3 value in correct endian format. Without this patch when MCE handler, after recovery, returns to code that that caused the MCE may end up with Data SLB access interrupt for invalid address followed by kernel panic or hang. Severe Machine check interrupt [Recovered] NIP [d00000000ca301b8]: init_module+0x1b8/0x338 [bork_kernel] Initiator: CPU Error type: SLB [Multihit] Effective address: d00000000ca70000 cpu 0xa: Vector: 380 (Data SLB Access) at [c0000000fc7775b0] pc: c0000000009694c0: vsnprintf+0x80/0x480 lr: c0000000009698e0: vscnprintf+0x20/0x60 sp: c0000000fc777830 msr: 8000000002009033 dar: a803a30c000000d0 current = 0xc00000000bc9ef00 paca = 0xc00000001eca5c00 softe: 3 irq_happened: 0x01 pid = 8860, comm = insmod vscnprintf+0x20/0x60 vprintk_emit+0xb4/0x4b0 vprintk_func+0x5c/0xd0 printk+0x38/0x4c init_module+0x1c0/0x338 [bork_kernel] do_one_initcall+0x54/0x230 do_init_module+0x8c/0x248 load_module+0x12b8/0x15b0 sys_finit_module+0xa8/0x110 system_call+0x58/0x6c --- Exception: c00 (System Call) at 00007fff8bda0644 SP (7fffdfbfe980) is in userspace This patch fixes this issue. Fixes: a08a53ea4c97 ("powerpc/le: Enable RTAS events support") Cc: stable@vger.kernel.org # v3.15+ Reviewed-by: Nicholas Piggin Signed-off-by: Mahesh Salgaonkar Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/ras.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index d263f7bc80fc..c85c76dc4400 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -298,7 +298,7 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) } savep = __va(regs->gpr[3]); - regs->gpr[3] = savep[0]; /* restore original r3 */ + regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */ /* If it isn't an extended log we can use the per cpu 64bit buffer */ h = (struct rtas_error_log *)&savep[1]; From fd38cf65a88ec9dc2be3ebac91d08cc137bdf8bd Mon Sep 17 00:00:00 2001 From: jiangyiwen Date: Fri, 3 Aug 2018 12:11:34 +0800 Subject: [PATCH 365/392] 9p/virtio: fix off-by-one error in sg list bounds check commit 23cba9cbde0bba05d772b335fe5f66aa82b9ad19 upstream. Because the value of limit is VIRTQUEUE_NUM, if index is equal to limit, it will cause sg array out of bounds, so correct the judgement of BUG_ON. Link: http://lkml.kernel.org/r/5B63D5F6.6080109@huawei.com Signed-off-by: Yiwen Jiang Reported-By: Dan Carpenter Acked-by: Jun Piao Cc: stable@vger.kernel.org Signed-off-by: Dominique Martinet Signed-off-by: Greg Kroah-Hartman --- net/9p/trans_virtio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 071ac5c495fc..d62df2747682 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -192,7 +192,7 @@ static int pack_sg_list(struct scatterlist *sg, int start, s = rest_of_page(data); if (s > count) s = count; - BUG_ON(index > limit); + BUG_ON(index >= limit); /* Make sure we don't terminate early. */ sg_unmark_end(&sg[index]); sg_set_buf(&sg[index++], data, s); @@ -238,6 +238,7 @@ pack_sg_list_p(struct scatterlist *sg, int start, int limit, s = rest_of_page(data); if (s > count) s = count; + BUG_ON(index >= limit); /* Make sure we don't terminate early. */ sg_unmark_end(&sg[index]); sg_set_page(&sg[index++], pdata[i++], s, data_off); From 7bba0ec33b0b17d1b1609f992825f5b162304738 Mon Sep 17 00:00:00 2001 From: Tomas Bortoli Date: Tue, 10 Jul 2018 00:29:43 +0200 Subject: [PATCH 366/392] net/9p/client.c: version pointer uninitialized commit 7913690dcc5e18e235769fd87c34143072f5dbea upstream. The p9_client_version() does not initialize the version pointer. If the call to p9pdu_readf() returns an error and version has not been allocated in p9pdu_readf(), then the program will jump to the "error" label and will try to free the version pointer. If version is not initialized, free() will be called with uninitialized, garbage data and will provoke a crash. Link: http://lkml.kernel.org/r/20180709222943.19503-1-tomasbortoli@gmail.com Signed-off-by: Tomas Bortoli Reported-by: syzbot+65c6b72f284a39d416b4@syzkaller.appspotmail.com Reviewed-by: Jun Piao Reviewed-by: Yiwen Jiang Cc: Eric Van Hensbergen Cc: Ron Minnich Cc: Latchesar Ionkov Signed-off-by: Andrew Morton Cc: stable@vger.kernel.org Signed-off-by: Dominique Martinet Signed-off-by: Greg Kroah-Hartman --- net/9p/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/9p/client.c b/net/9p/client.c index f24b774d2215..7122b32b310f 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -938,7 +938,7 @@ static int p9_client_version(struct p9_client *c) { int err = 0; struct p9_req_t *req; - char *version; + char *version = NULL; int msize; p9_debug(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n", From d90fb2996470afa3d416f7dbafc6482177e2a11e Mon Sep 17 00:00:00 2001 From: Tomas Bortoli Date: Fri, 20 Jul 2018 11:27:30 +0200 Subject: [PATCH 367/392] net/9p/trans_fd.c: fix race-condition by flushing workqueue before the kfree() commit 430ac66eb4c5b5c4eb846b78ebf65747510b30f1 upstream. The patch adds the flush in p9_mux_poll_stop() as it the function used by p9_conn_destroy(), in turn called by p9_fd_close() to stop the async polling associated with the data regarding the connection. Link: http://lkml.kernel.org/r/20180720092730.27104-1-tomasbortoli@gmail.com Signed-off-by: Tomas Bortoli Reported-by: syzbot+39749ed7d9ef6dfb23f6@syzkaller.appspotmail.com To: Eric Van Hensbergen To: Ron Minnich To: Latchesar Ionkov Cc: Yiwen Jiang Cc: stable@vger.kernel.org Signed-off-by: Dominique Martinet Signed-off-by: Greg Kroah-Hartman --- net/9p/trans_fd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 80d08f6664cb..e0de928c9827 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -185,6 +185,8 @@ static void p9_mux_poll_stop(struct p9_conn *m) spin_lock_irqsave(&p9_poll_lock, flags); list_del_init(&m->poll_pending_link); spin_unlock_irqrestore(&p9_poll_lock, flags); + + flush_work(&p9_poll_work); } /** From ceef7b21cdfb9c3ba31f2945643f918dadab6382 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 2 Aug 2018 16:08:52 -0400 Subject: [PATCH 368/392] dm cache metadata: save in-core policy_hint_size to on-disk superblock commit fd2fa95416188a767a63979296fa3e169a9ef5ec upstream. policy_hint_size starts as 0 during __write_initial_superblock(). It isn't until the policy is loaded that policy_hint_size is set in-core (cmd->policy_hint_size). But it never got recorded in the on-disk superblock because __commit_transaction() didn't deal with transfering the in-core cmd->policy_hint_size to the on-disk superblock. The in-core cmd->policy_hint_size gets initialized by metadata_open()'s __begin_transaction_flags() which re-reads all superblock fields. Because the superblock's policy_hint_size was never properly stored, when the cache was created, hints_array_available() would always return false when re-activating a previously created cache. This means __load_mappings() always considered the hints invalid and never made use of the hints (these hints served to optimize). Another detremental side-effect of this oversight is the cache_check utility would fail with: "invalid hint width: 0" Cc: stable@vger.kernel.org Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-cache-metadata.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index 1e64e9c50d85..aeb9ee6082d9 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c @@ -324,7 +324,7 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd) disk_super->version = cpu_to_le32(MAX_CACHE_VERSION); memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name)); memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version)); - disk_super->policy_hint_size = 0; + disk_super->policy_hint_size = cpu_to_le32(0); __copy_sm_root(cmd, disk_super); @@ -635,6 +635,7 @@ static int __commit_transaction(struct dm_cache_metadata *cmd, disk_super->policy_version[0] = cpu_to_le32(cmd->policy_version[0]); disk_super->policy_version[1] = cpu_to_le32(cmd->policy_version[1]); disk_super->policy_version[2] = cpu_to_le32(cmd->policy_version[2]); + disk_super->policy_hint_size = cpu_to_le32(cmd->policy_hint_size); disk_super->read_hits = cpu_to_le32(cmd->stats.read_hits); disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses); From a3442d68f5af35117f20f595c530ca6c26992f22 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 25 Jun 2018 11:03:07 +0300 Subject: [PATCH 369/392] iio: ad9523: Fix displayed phase commit 5a4e33c1c53ae7d4425f7d94e60e4458a37b349e upstream. Fix the displayed phase for the ad9523 driver. Currently the most significant decimal place is dropped and all other digits are shifted one to the left. This is due to a multiplication by 10, which is not necessary, so remove it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Alexandru Ardelean Fixes: cd1678f9632 ("iio: frequency: New driver for AD9523 SPI Low Jitter Clock Generator") Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/frequency/ad9523.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index 7c5245d9f99c..abc21d913ef0 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -641,7 +641,7 @@ static int ad9523_read_raw(struct iio_dev *indio_dev, code = (AD9523_CLK_DIST_DIV_PHASE_REV(ret) * 3141592) / AD9523_CLK_DIST_DIV_REV(ret); *val = code / 1000000; - *val2 = (code % 1000000) * 10; + *val2 = code % 1000000; return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; From 76eb62bdb1119b400668b0e63cce3edc1678dea6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 27 Jul 2018 09:42:45 +0300 Subject: [PATCH 370/392] iio: ad9523: Fix return value for ad952x_store() commit 9a5094ca29ea9b1da301b31fd377c0c0c4c23034 upstream. A sysfs write callback function needs to either return the number of consumed characters or an error. The ad952x_store() function currently returns 0 if the input value was "0", this will signal that no characters have been consumed and the function will be called repeatedly in a loop indefinitely. Fix this by returning number of supplied characters to indicate that the whole input string has been consumed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Alexandru Ardelean Fixes: cd1678f96329 ("iio: frequency: New driver for AD9523 SPI Low Jitter Clock Generator") Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/frequency/ad9523.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index abc21d913ef0..4cffd8fc5cae 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -507,7 +507,7 @@ static ssize_t ad9523_store(struct device *dev, return ret; if (!state) - return 0; + return len; mutex_lock(&indio_dev->mlock); switch ((u32)this_attr->address) { From 38a39e3dd4494902e1ad8aa8e0d71c9268e73de3 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 1 Aug 2018 15:40:57 -0400 Subject: [PATCH 371/392] tracing: Do not call start/stop() functions when tracing_on does not change commit f143641bfef9a4a60c57af30de26c63057e7e695 upstream. Currently, when one echo's in 1 into tracing_on, the current tracer's "start()" function is executed, even if tracing_on was already one. This can lead to strange side effects. One being that if the hwlat tracer is enabled, and someone does "echo 1 > tracing_on" into tracing_on, the hwlat tracer's start() function is called again which will recreate another kernel thread, and make it unable to remove the old one. Link: http://lkml.kernel.org/r/1533120354-22923-1-git-send-email-erica.bugden@linutronix.de Cc: stable@vger.kernel.org Fixes: 2df8f8a6a897e ("tracing: Fix regression with irqsoff tracer and tracing_on file") Reported-by: Erica Bugden Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 521da2cfeb4f..69af9a1b1031 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -6209,7 +6209,9 @@ rb_simple_write(struct file *filp, const char __user *ubuf, if (buffer) { mutex_lock(&trace_types_lock); - if (val) { + if (!!val == tracer_tracing_is_on(tr)) { + val = 0; /* do nothing */ + } else if (val) { tracer_tracing_on(tr); if (tr->current_trace->start) tr->current_trace->start(tr); From a5a4dfa99f195c1dde1f6c77e43238c35c363092 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Thu, 16 Aug 2018 16:08:37 -0400 Subject: [PATCH 372/392] tracing/blktrace: Fix to allow setting same value commit 757d9140072054528b13bbe291583d9823cde195 upstream. Masami Hiramatsu reported: Current trace-enable attribute in sysfs returns an error if user writes the same setting value as current one, e.g. # cat /sys/block/sda/trace/enable 0 # echo 0 > /sys/block/sda/trace/enable bash: echo: write error: Invalid argument # echo 1 > /sys/block/sda/trace/enable # echo 1 > /sys/block/sda/trace/enable bash: echo: write error: Device or resource busy But this is not a preferred behavior, it should ignore if new setting is same as current one. This fixes the problem as below. # cat /sys/block/sda/trace/enable 0 # echo 0 > /sys/block/sda/trace/enable # echo 1 > /sys/block/sda/trace/enable # echo 1 > /sys/block/sda/trace/enable Link: http://lkml.kernel.org/r/20180816103802.08678002@gandalf.local.home Cc: Ingo Molnar Cc: Jens Axboe Cc: linux-block@vger.kernel.org Cc: stable@vger.kernel.org Fixes: cd649b8bb830d ("blktrace: remove sysfs_blk_trace_enable_show/store()") Reported-by: Masami Hiramatsu Tested-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- kernel/trace/blktrace.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index c1bd4ada2a04..2edfa4b4ccb1 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -1734,6 +1734,10 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev, mutex_lock(&bdev->bd_mutex); if (attr == &dev_attr_enable) { + if (!!value == !!q->blk_trace) { + ret = 0; + goto out_unlock_bdev; + } if (value) ret = blk_trace_setup_queue(q, bdev); else From 73b5c3dc570d96e671f3ce5537ebda70237b4181 Mon Sep 17 00:00:00 2001 From: Snild Dolkow Date: Thu, 26 Jul 2018 09:15:39 +0200 Subject: [PATCH 373/392] kthread, tracing: Don't expose half-written comm when creating kthreads commit 3e536e222f2930534c252c1cc7ae799c725c5ff9 upstream. There is a window for racing when printing directly to task->comm, allowing other threads to see a non-terminated string. The vsnprintf function fills the buffer, counts the truncated chars, then finally writes the \0 at the end. creator other vsnprintf: fill (not terminated) count the rest trace_sched_waking(p): ... memcpy(comm, p->comm, TASK_COMM_LEN) write \0 The consequences depend on how 'other' uses the string. In our case, it was copied into the tracing system's saved cmdlines, a buffer of adjacent TASK_COMM_LEN-byte buffers (note the 'n' where 0 should be): crash-arm64> x/1024s savedcmd->saved_cmdlines | grep 'evenk' 0xffffffd5b3818640: "irq/497-pwr_evenkworker/u16:12" ...and a strcpy out of there would cause stack corruption: [224761.522292] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffff9bf9783c78 crash-arm64> kbt | grep 'comm\|trace_print_context' #6 0xffffff9bf9783c78 in trace_print_context+0x18c(+396) comm (char [16]) = "irq/497-pwr_even" crash-arm64> rd 0xffffffd4d0e17d14 8 ffffffd4d0e17d14: 2f71726900000000 5f7277702d373934 ....irq/497-pwr_ ffffffd4d0e17d24: 726f776b6e657665 3a3631752f72656b evenkworker/u16: ffffffd4d0e17d34: f9780248ff003231 cede60e0ffffff9b 12..H.x......`.. ffffffd4d0e17d44: cede60c8ffffffd4 00000fffffffffd4 .....`.......... The workaround in e09e28671 (use strlcpy in __trace_find_cmdline) was likely needed because of this same bug. Solved by vsnprintf:ing to a local buffer, then using set_task_comm(). This way, there won't be a window where comm is not terminated. Link: http://lkml.kernel.org/r/20180726071539.188015-1-snild@sony.com Cc: stable@vger.kernel.org Fixes: bc0c38d139ec7 ("ftrace: latency tracer infrastructure") Reviewed-by: Steven Rostedt (VMware) Signed-off-by: Snild Dolkow Signed-off-by: Steven Rostedt (VMware) [backported to 3.18 / 4.4 by Snild] Signed-off-by: Greg Kroah-Hartman --- kernel/kthread.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/kthread.c b/kernel/kthread.c index c7effb3a3b82..3b88f4aefe4d 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -309,10 +309,16 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), task = create->result; if (!IS_ERR(task)) { static const struct sched_param param = { .sched_priority = 0 }; + char name[TASK_COMM_LEN]; va_list args; va_start(args, namefmt); - vsnprintf(task->comm, sizeof(task->comm), namefmt, args); + /* + * task is already visible to other tasks, so updating + * COMM must be protected. + */ + vsnprintf(name, sizeof(name), namefmt, args); + set_task_comm(task, name); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. From eb67901b5d617eeca2939699a3aa5e06c3ea4fe2 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Thu, 9 Aug 2018 15:37:59 -0400 Subject: [PATCH 374/392] uprobes: Use synchronize_rcu() not synchronize_sched() commit 016f8ffc48cb01d1e7701649c728c5d2e737d295 upstream. While debugging another bug, I was looking at all the synchronize*() functions being used in kernel/trace, and noticed that trace_uprobes was using synchronize_sched(), with a comment to synchronize with {u,ret}_probe_trace_func(). When looking at those functions, the data is protected with "rcu_read_lock()" and not with "rcu_read_lock_sched()". This is using the wrong synchronize_*() function. Link: http://lkml.kernel.org/r/20180809160553.469e1e32@gandalf.local.home Cc: stable@vger.kernel.org Fixes: 70ed91c6ec7f8 ("tracing/uprobes: Support ftrace_event_file base multibuffer") Acked-by: Oleg Nesterov Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_uprobe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index f7e75f3dfcb2..a4c3219ec62d 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -957,7 +957,7 @@ probe_event_disable(struct trace_uprobe *tu, struct ftrace_event_file *file) list_del_rcu(&link->list); /* synchronize with u{,ret}probe_trace_func */ - synchronize_sched(); + synchronize_rcu(); kfree(link); if (!list_empty(&tu->tp.files)) From 02de522ac047a34433b9718173a77bd0cc806485 Mon Sep 17 00:00:00 2001 From: Tomas Bortoli Date: Fri, 27 Jul 2018 13:05:58 +0200 Subject: [PATCH 375/392] 9p: fix multiple NULL-pointer-dereferences commit 10aa14527f458e9867cf3d2cc6b8cb0f6704448b upstream. Added checks to prevent GPFs from raising. Link: http://lkml.kernel.org/r/20180727110558.5479-1-tomasbortoli@gmail.com Signed-off-by: Tomas Bortoli Reported-by: syzbot+1a262da37d3bead15c39@syzkaller.appspotmail.com Cc: stable@vger.kernel.org Signed-off-by: Dominique Martinet Signed-off-by: Greg Kroah-Hartman --- net/9p/trans_fd.c | 5 ++++- net/9p/trans_rdma.c | 3 +++ net/9p/trans_virtio.c | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index e0de928c9827..9d935dc71b83 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -934,7 +934,7 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args) if (err < 0) return err; - if (valid_ipaddr4(addr) < 0) + if (addr == NULL || valid_ipaddr4(addr) < 0) return -EINVAL; csocket = NULL; @@ -982,6 +982,9 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args) csocket = NULL; + if (addr == NULL) + return -EINVAL; + if (strlen(addr) >= UNIX_PATH_MAX) { pr_err("%s (%d): address too long: %s\n", __func__, task_pid_nr(current), addr); diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index 14ad43b5cf89..d00cb890398b 100644 --- a/net/9p/trans_rdma.c +++ b/net/9p/trans_rdma.c @@ -623,6 +623,9 @@ rdma_create_trans(struct p9_client *client, const char *addr, char *args) struct ib_qp_init_attr qp_attr; struct ib_device_attr devattr; + if (addr == NULL) + return -EINVAL; + /* Parse the transport specific mount options */ err = parse_opts(args, &opts); if (err < 0) diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index d62df2747682..130180f67ae3 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -617,6 +617,9 @@ p9_virtio_create(struct p9_client *client, const char *devname, char *args) int ret = -ENOENT; int found = 0; + if (devname == NULL) + return -EINVAL; + mutex_lock(&virtio_9p_lock); list_for_each_entry(chan, &virtio_chan_list, chan_list) { if (!strncmp(devname, chan->tag, chan->tag_len) && From 86e40c0ccb044d265fdc54c5865b4adaea8d3841 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 4 Jul 2018 12:59:58 +0300 Subject: [PATCH 376/392] pnfs/blocklayout: off by one in bl_map_stripe() commit 0914bb965e38a055e9245637aed117efbe976e91 upstream. "dev->nr_children" is the number of children which were parsed successfully in bl_parse_stripe(). It could be all of them and then, in that case, it is equal to v->stripe.volumes_count. Either way, the > should be >= so that we don't go beyond the end of what we're supposed to. Fixes: 5c83746a0cf2 ("pnfs/blocklayout: in-kernel GETDEVICEINFO XDR parsing") Signed-off-by: Dan Carpenter Reviewed-by: Christoph Hellwig Cc: stable@vger.kernel.org # 3.17+ Signed-off-by: Anna Schumaker Signed-off-by: Greg Kroah-Hartman --- fs/nfs/blocklayout/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/blocklayout/dev.c b/fs/nfs/blocklayout/dev.c index 5aed4f98df41..00727659e439 100644 --- a/fs/nfs/blocklayout/dev.c +++ b/fs/nfs/blocklayout/dev.c @@ -157,7 +157,7 @@ static bool bl_map_stripe(struct pnfs_block_dev *dev, u64 offset, chunk = div_u64(offset, dev->chunk_size); div_u64_rem(chunk, dev->nr_children, &chunk_idx); - if (chunk_idx > dev->nr_children) { + if (chunk_idx >= dev->nr_children) { dprintk("%s: invalid chunk idx %d (%lld/%lld)\n", __func__, chunk_idx, offset, dev->chunk_size); /* error, should not happen */ From 8c6a5c96a60dcdb209e4b6e8373fb6207a9fb69c Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 3 Jul 2018 09:59:47 +0100 Subject: [PATCH 377/392] ARM: tegra: Fix Tegra30 Cardhu PCA954x reset commit 6e1811900b6fe6f2b4665dba6bd6ed32c6b98575 upstream. On all versions of Tegra30 Cardhu, the reset signal to the NXP PCA9546 I2C mux is connected to the Tegra GPIO BB0. Currently, this pin on the Tegra is not configured as a GPIO but as a special-function IO (SFIO) that is multiplexing the pin to an I2S controller. On exiting system suspend, I2C commands sent to the PCA9546 are failing because there is no ACK. Although it is not possible to see exactly what is happening to the reset during suspend, by ensuring it is configured as a GPIO and driven high, to de-assert the reset, the failures are no longer seen. Please note that this GPIO is also used to drive the reset signal going to the camera connector on the board. However, given that there is no camera support currently for Cardhu, this should not have any impact. Fixes: 40431d16ff11 ("ARM: tegra: enable PCA9546 on Cardhu") Cc: stable@vger.kernel.org Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/tegra30-cardhu.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index a1b682ea01bd..224a7605877e 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi @@ -200,6 +200,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x70>; + reset-gpio = <&gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_LOW>; }; }; From 76b5c9f1a9b0ca8ccfb704eb21cab0e304bb3876 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 22 Aug 2018 17:30:14 +0200 Subject: [PATCH 378/392] mm/tlb: Remove tlb_remove_table() non-concurrent condition commit a6f572084fbee8b30f91465f4a085d7a90901c57 upstream. Will noted that only checking mm_users is incorrect; we should also check mm_count in order to cover CPUs that have a lazy reference to this mm (and could do speculative TLB operations). If removing this turns out to be a performance issue, we can re-instate a more complete check, but in tlb_table_flush() eliding the call_rcu_sched(). Fixes: 267239116987 ("mm, powerpc: move the RCU page-table freeing into generic code") Reported-by: Will Deacon Signed-off-by: Peter Zijlstra (Intel) Acked-by: Rik van Riel Acked-by: Will Deacon Cc: Nicholas Piggin Cc: David Miller Cc: Martin Schwidefsky Cc: Michael Ellerman Cc: stable@kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/memory.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 003966808b3a..84778b39f8d8 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -359,15 +359,6 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table) { struct mmu_table_batch **batch = &tlb->batch; - /* - * When there's less then two users of this mm there cannot be a - * concurrent page-table walk. - */ - if (atomic_read(&tlb->mm->mm_users) < 2) { - __tlb_remove_table(table); - return; - } - if (*batch == NULL) { *batch = (struct mmu_table_batch *)__get_free_page(GFP_NOWAIT | __GFP_NOWARN); if (*batch == NULL) { From 3680c7ecdc05e35d6ed1d7d269ecc8a03dae0748 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 13 May 2017 21:39:49 -0400 Subject: [PATCH 379/392] osf_getdomainname(): use copy_to_user() commit 9ba3eb5103cf56f0daaf07de4507df76e7813ed7 upstream. Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- arch/alpha/kernel/osf_sys.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index cb34a25a0168..81311ad5de59 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -560,25 +560,20 @@ SYSCALL_DEFINE0(getdtablesize) */ SYSCALL_DEFINE2(osf_getdomainname, char __user *, name, int, namelen) { - unsigned len; - int i; + int len, err = 0; + char *kname; - if (!access_ok(VERIFY_WRITE, name, namelen)) - return -EFAULT; - - len = namelen; - if (len > 32) - len = 32; + if (namelen > 32) + namelen = 32; down_read(&uts_sem); - for (i = 0; i < len; ++i) { - __put_user(utsname()->domainname[i], name + i); - if (utsname()->domainname[i] == '\0') - break; - } + kname = utsname()->domainname; + len = strnlen(kname, namelen); + if (copy_to_user(name, kname, min(len + 1, namelen))) + err = -EFAULT; up_read(&uts_sem); - return 0; + return err; } /* From a1ca395b1796c1e998e4ebf237c2d559b326d36c Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Mon, 25 Jun 2018 18:34:10 +0200 Subject: [PATCH 380/392] sys: don't hold uts_sem while accessing userspace memory commit 42a0cc3478584d4d63f68f2f5af021ddbea771fa upstream. Holding uts_sem as a writer while accessing userspace memory allows a namespace admin to stall all processes that attempt to take uts_sem. Instead, move data through stack buffers and don't access userspace memory while uts_sem is held. Cc: stable@vger.kernel.org Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Jann Horn Signed-off-by: Eric W. Biederman Signed-off-by: Greg Kroah-Hartman --- arch/alpha/kernel/osf_sys.c | 51 ++++++++--------- arch/sparc/kernel/sys_sparc_32.c | 22 +++++--- arch/sparc/kernel/sys_sparc_64.c | 20 ++++--- kernel/sys.c | 95 +++++++++++++++----------------- kernel/utsname_sysctl.c | 41 ++++++++------ 5 files changed, 119 insertions(+), 110 deletions(-) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 81311ad5de59..755554ebd9dc 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -525,24 +525,19 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path, SYSCALL_DEFINE1(osf_utsname, char __user *, name) { int error; + char tmp[5 * 32]; down_read(&uts_sem); - error = -EFAULT; - if (copy_to_user(name + 0, utsname()->sysname, 32)) - goto out; - if (copy_to_user(name + 32, utsname()->nodename, 32)) - goto out; - if (copy_to_user(name + 64, utsname()->release, 32)) - goto out; - if (copy_to_user(name + 96, utsname()->version, 32)) - goto out; - if (copy_to_user(name + 128, utsname()->machine, 32)) - goto out; + memcpy(tmp + 0 * 32, utsname()->sysname, 32); + memcpy(tmp + 1 * 32, utsname()->nodename, 32); + memcpy(tmp + 2 * 32, utsname()->release, 32); + memcpy(tmp + 3 * 32, utsname()->version, 32); + memcpy(tmp + 4 * 32, utsname()->machine, 32); + up_read(&uts_sem); - error = 0; - out: - up_read(&uts_sem); - return error; + if (copy_to_user(name, tmp, sizeof(tmp))) + return -EFAULT; + return 0; } SYSCALL_DEFINE0(getpagesize) @@ -562,18 +557,21 @@ SYSCALL_DEFINE2(osf_getdomainname, char __user *, name, int, namelen) { int len, err = 0; char *kname; + char tmp[32]; - if (namelen > 32) + if (namelen < 0 || namelen > 32) namelen = 32; down_read(&uts_sem); kname = utsname()->domainname; len = strnlen(kname, namelen); - if (copy_to_user(name, kname, min(len + 1, namelen))) - err = -EFAULT; + len = min(len + 1, namelen); + memcpy(tmp, kname, len); up_read(&uts_sem); - return err; + if (copy_to_user(name, tmp, len)) + return -EFAULT; + return 0; } /* @@ -735,13 +733,14 @@ SYSCALL_DEFINE3(osf_sysinfo, int, command, char __user *, buf, long, count) }; unsigned long offset; const char *res; - long len, err = -EINVAL; + long len; + char tmp[__NEW_UTS_LEN + 1]; offset = command-1; if (offset >= ARRAY_SIZE(sysinfo_table)) { /* Digital UNIX has a few unpublished interfaces here */ printk("sysinfo(%d)", command); - goto out; + return -EINVAL; } down_read(&uts_sem); @@ -749,13 +748,11 @@ SYSCALL_DEFINE3(osf_sysinfo, int, command, char __user *, buf, long, count) len = strlen(res)+1; if ((unsigned long)len > (unsigned long)count) len = count; - if (copy_to_user(buf, res, len)) - err = -EFAULT; - else - err = 0; + memcpy(tmp, res, len); up_read(&uts_sem); - out: - return err; + if (copy_to_user(buf, tmp, len)) + return -EFAULT; + return 0; } SYSCALL_DEFINE5(osf_getsysinfo, unsigned long, op, void __user *, buffer, diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index 646988d4c1a3..740f43b9b541 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -201,23 +201,27 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, asmlinkage long sys_getdomainname(char __user *name, int len) { - int nlen, err; - + int nlen, err; + char tmp[__NEW_UTS_LEN + 1]; + if (len < 0) return -EINVAL; - down_read(&uts_sem); - + down_read(&uts_sem); + nlen = strlen(utsname()->domainname) + 1; err = -EINVAL; if (nlen > len) - goto out; + goto out_unlock; + memcpy(tmp, utsname()->domainname, nlen); - err = -EFAULT; - if (!copy_to_user(name, utsname()->domainname, nlen)) - err = 0; + up_read(&uts_sem); -out: + if (copy_to_user(name, tmp, nlen)) + return -EFAULT; + return 0; + +out_unlock: up_read(&uts_sem); return err; } diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 7f0f7c01b297..f63cd2ea8470 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -524,23 +524,27 @@ extern void check_pending(int signum); SYSCALL_DEFINE2(getdomainname, char __user *, name, int, len) { - int nlen, err; + int nlen, err; + char tmp[__NEW_UTS_LEN + 1]; if (len < 0) return -EINVAL; - down_read(&uts_sem); - + down_read(&uts_sem); + nlen = strlen(utsname()->domainname) + 1; err = -EINVAL; if (nlen > len) - goto out; + goto out_unlock; + memcpy(tmp, utsname()->domainname, nlen); + + up_read(&uts_sem); - err = -EFAULT; - if (!copy_to_user(name, utsname()->domainname, nlen)) - err = 0; + if (copy_to_user(name, tmp, nlen)) + return -EFAULT; + return 0; -out: +out_unlock: up_read(&uts_sem); return err; } diff --git a/kernel/sys.c b/kernel/sys.c index 1eaa2f0b0246..aa37d8662bb3 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1125,18 +1125,19 @@ static int override_release(char __user *release, size_t len) SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) { - int errno = 0; + struct new_utsname tmp; down_read(&uts_sem); - if (copy_to_user(name, utsname(), sizeof *name)) - errno = -EFAULT; + memcpy(&tmp, utsname(), sizeof(tmp)); up_read(&uts_sem); + if (copy_to_user(name, &tmp, sizeof(tmp))) + return -EFAULT; - if (!errno && override_release(name->release, sizeof(name->release))) - errno = -EFAULT; - if (!errno && override_architecture(name)) - errno = -EFAULT; - return errno; + if (override_release(name->release, sizeof(name->release))) + return -EFAULT; + if (override_architecture(name)) + return -EFAULT; + return 0; } #ifdef __ARCH_WANT_SYS_OLD_UNAME @@ -1145,55 +1146,46 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) */ SYSCALL_DEFINE1(uname, struct old_utsname __user *, name) { - int error = 0; + struct old_utsname tmp; if (!name) return -EFAULT; down_read(&uts_sem); - if (copy_to_user(name, utsname(), sizeof(*name))) - error = -EFAULT; + memcpy(&tmp, utsname(), sizeof(tmp)); up_read(&uts_sem); + if (copy_to_user(name, &tmp, sizeof(tmp))) + return -EFAULT; - if (!error && override_release(name->release, sizeof(name->release))) - error = -EFAULT; - if (!error && override_architecture(name)) - error = -EFAULT; - return error; + if (override_release(name->release, sizeof(name->release))) + return -EFAULT; + if (override_architecture(name)) + return -EFAULT; + return 0; } SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name) { - int error; + struct oldold_utsname tmp = {}; if (!name) return -EFAULT; - if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname))) - return -EFAULT; down_read(&uts_sem); - error = __copy_to_user(&name->sysname, &utsname()->sysname, - __OLD_UTS_LEN); - error |= __put_user(0, name->sysname + __OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename, &utsname()->nodename, - __OLD_UTS_LEN); - error |= __put_user(0, name->nodename + __OLD_UTS_LEN); - error |= __copy_to_user(&name->release, &utsname()->release, - __OLD_UTS_LEN); - error |= __put_user(0, name->release + __OLD_UTS_LEN); - error |= __copy_to_user(&name->version, &utsname()->version, - __OLD_UTS_LEN); - error |= __put_user(0, name->version + __OLD_UTS_LEN); - error |= __copy_to_user(&name->machine, &utsname()->machine, - __OLD_UTS_LEN); - error |= __put_user(0, name->machine + __OLD_UTS_LEN); + memcpy(&tmp.sysname, &utsname()->sysname, __OLD_UTS_LEN); + memcpy(&tmp.nodename, &utsname()->nodename, __OLD_UTS_LEN); + memcpy(&tmp.release, &utsname()->release, __OLD_UTS_LEN); + memcpy(&tmp.version, &utsname()->version, __OLD_UTS_LEN); + memcpy(&tmp.machine, &utsname()->machine, __OLD_UTS_LEN); up_read(&uts_sem); + if (copy_to_user(name, &tmp, sizeof(tmp))) + return -EFAULT; - if (!error && override_architecture(name)) - error = -EFAULT; - if (!error && override_release(name->release, sizeof(name->release))) - error = -EFAULT; - return error ? -EFAULT : 0; + if (override_architecture(name)) + return -EFAULT; + if (override_release(name->release, sizeof(name->release))) + return -EFAULT; + return 0; } #endif @@ -1207,17 +1199,18 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; - down_write(&uts_sem); errno = -EFAULT; if (!copy_from_user(tmp, name, len)) { - struct new_utsname *u = utsname(); + struct new_utsname *u; + down_write(&uts_sem); + u = utsname(); memcpy(u->nodename, tmp, len); memset(u->nodename + len, 0, sizeof(u->nodename) - len); errno = 0; uts_proc_notify(UTS_PROC_HOSTNAME); + up_write(&uts_sem); } - up_write(&uts_sem); return errno; } @@ -1225,8 +1218,9 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) SYSCALL_DEFINE2(gethostname, char __user *, name, int, len) { - int i, errno; + int i; struct new_utsname *u; + char tmp[__NEW_UTS_LEN + 1]; if (len < 0) return -EINVAL; @@ -1235,11 +1229,11 @@ SYSCALL_DEFINE2(gethostname, char __user *, name, int, len) i = 1 + strlen(u->nodename); if (i > len) i = len; - errno = 0; - if (copy_to_user(name, u->nodename, i)) - errno = -EFAULT; + memcpy(tmp, u->nodename, i); up_read(&uts_sem); - return errno; + if (copy_to_user(name, tmp, i)) + return -EFAULT; + return 0; } #endif @@ -1258,17 +1252,18 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; - down_write(&uts_sem); errno = -EFAULT; if (!copy_from_user(tmp, name, len)) { - struct new_utsname *u = utsname(); + struct new_utsname *u; + down_write(&uts_sem); + u = utsname(); memcpy(u->domainname, tmp, len); memset(u->domainname + len, 0, sizeof(u->domainname) - len); errno = 0; uts_proc_notify(UTS_PROC_DOMAINNAME); + up_write(&uts_sem); } - up_write(&uts_sem); return errno; } diff --git a/kernel/utsname_sysctl.c b/kernel/utsname_sysctl.c index c8eac43267e9..d2b3b2973456 100644 --- a/kernel/utsname_sysctl.c +++ b/kernel/utsname_sysctl.c @@ -17,7 +17,7 @@ #ifdef CONFIG_PROC_SYSCTL -static void *get_uts(struct ctl_table *table, int write) +static void *get_uts(struct ctl_table *table) { char *which = table->data; struct uts_namespace *uts_ns; @@ -25,21 +25,9 @@ static void *get_uts(struct ctl_table *table, int write) uts_ns = current->nsproxy->uts_ns; which = (which - (char *)&init_uts_ns) + (char *)uts_ns; - if (!write) - down_read(&uts_sem); - else - down_write(&uts_sem); return which; } -static void put_uts(struct ctl_table *table, int write, void *which) -{ - if (!write) - up_read(&uts_sem); - else - up_write(&uts_sem); -} - /* * Special case of dostring for the UTS structure. This has locks * to observe. Should this be in kernel/sys.c ???? @@ -49,13 +37,34 @@ static int proc_do_uts_string(struct ctl_table *table, int write, { struct ctl_table uts_table; int r; + char tmp_data[__NEW_UTS_LEN + 1]; + memcpy(&uts_table, table, sizeof(uts_table)); - uts_table.data = get_uts(table, write); + uts_table.data = tmp_data; + + /* + * Buffer the value in tmp_data so that proc_dostring() can be called + * without holding any locks. + * We also need to read the original value in the write==1 case to + * support partial writes. + */ + down_read(&uts_sem); + memcpy(tmp_data, get_uts(table), sizeof(tmp_data)); + up_read(&uts_sem); r = proc_dostring(&uts_table, write, buffer, lenp, ppos); - put_uts(table, write, uts_table.data); - if (write) + if (write) { + /* + * Write back the new value. + * Note that, since we dropped uts_sem, the result can + * theoretically be incorrect if there are two parallel writes + * at non-zero offsets to the same sysctl. + */ + down_write(&uts_sem); + memcpy(get_uts(table), tmp_data, sizeof(tmp_data)); + up_write(&uts_sem); proc_sys_poll_notify(table->poll); + } return r; } From 8a749f3ef97796d702b2da4106459d46c5bb1adb Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 5 Dec 2014 20:03:28 -0600 Subject: [PATCH 381/392] userns; Correct the comment in map_write commit 36476beac4f8ca9dc7722790b2e8ef0e8e51034e upstream. It is important that all maps are less than PAGE_SIZE or else setting the last byte of the buffer to '0' could write off the end of the allocated storage. Correct the misleading comment. Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman --- kernel/user_namespace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index a2e37c5d2f63..ad419b04c146 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -643,7 +643,7 @@ static ssize_t map_write(struct file *file, const char __user *buf, if (!page) goto out; - /* Only allow <= page size writes at the beginning of the file */ + /* Only allow < page size writes at the beginning of the file */ ret = -EINVAL; if ((*ppos != 0) || (count >= PAGE_SIZE)) goto out; From 7d024b6d8ff09d485a5b3a7b6ba1efc03cafbebc Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Mon, 25 Jun 2018 18:34:19 +0200 Subject: [PATCH 382/392] userns: move user access out of the mutex commit 5820f140edef111a9ea2ef414ab2428b8cb805b1 upstream. The old code would hold the userns_state_mutex indefinitely if memdup_user_nul stalled due to e.g. a userfault region. Prevent that by moving the memdup_user_nul in front of the mutex_lock(). Note: This changes the error precedence of invalid buf/count/*ppos vs map already written / capabilities missing. Fixes: 22d917d80e84 ("userns: Rework the user_namespace adding uid/gid...") Cc: stable@vger.kernel.org Signed-off-by: Jann Horn Acked-by: Christian Brauner Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman Signed-off-by: Greg Kroah-Hartman --- kernel/user_namespace.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index ad419b04c146..86517dba9f48 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -600,9 +600,26 @@ static ssize_t map_write(struct file *file, const char __user *buf, struct uid_gid_map new_map; unsigned idx; struct uid_gid_extent *extent = NULL; - unsigned long page = 0; + unsigned long page; char *kbuf, *pos, *next_line; - ssize_t ret = -EINVAL; + ssize_t ret; + + /* Only allow < page size writes at the beginning of the file */ + if ((*ppos != 0) || (count >= PAGE_SIZE)) + return -EINVAL; + + /* Get a buffer */ + page = __get_free_page(GFP_TEMPORARY); + kbuf = (char *) page; + if (!page) + return -ENOMEM; + + /* Slurp in the user data */ + if (copy_from_user(kbuf, buf, count)) { + free_page(page); + return -EFAULT; + } + kbuf[count] = '\0'; /* * The userns_state_mutex serializes all writes to any given map. @@ -636,24 +653,6 @@ static ssize_t map_write(struct file *file, const char __user *buf, if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN)) goto out; - /* Get a buffer */ - ret = -ENOMEM; - page = __get_free_page(GFP_TEMPORARY); - kbuf = (char *) page; - if (!page) - goto out; - - /* Only allow < page size writes at the beginning of the file */ - ret = -EINVAL; - if ((*ppos != 0) || (count >= PAGE_SIZE)) - goto out; - - /* Slurp in the user data */ - ret = -EFAULT; - if (copy_from_user(kbuf, buf, count)) - goto out; - kbuf[count] = '\0'; - /* Parse the user data */ ret = -EINVAL; pos = kbuf; From 155279d482be4d1171df78d481f171571415a202 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Tue, 12 Jun 2018 20:49:45 +0200 Subject: [PATCH 383/392] ubifs: Fix memory leak in lprobs self-check commit eef19816ada3abd56d9f20c88794cc2fea83ebb2 upstream. Allocate the buffer after we return early. Otherwise memory is being leaked. Cc: Fixes: 1e51764a3c2a ("UBIFS: add new flash file system") Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/lprops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c index 46190a7c42a6..a0ee59b3974a 100644 --- a/fs/ubifs/lprops.c +++ b/fs/ubifs/lprops.c @@ -1091,10 +1091,6 @@ static int scan_check_cb(struct ubifs_info *c, } } - buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL); - if (!buf) - return -ENOMEM; - /* * After an unclean unmount, empty and freeable LEBs * may contain garbage - do not scan them. @@ -1113,6 +1109,10 @@ static int scan_check_cb(struct ubifs_info *c, return LPT_SCAN_CONTINUE; } + buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL); + if (!buf) + return -ENOMEM; + sleb = ubifs_scan(c, lnum, 0, buf, 0); if (IS_ERR(sleb)) { ret = PTR_ERR(sleb); From d6510124f1aca5c958036eeb67d0bd57a277d791 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Sun, 1 Jul 2018 23:20:50 +0200 Subject: [PATCH 384/392] Revert "UBIFS: Fix potential integer overflow in allocation" commit 08acbdd6fd736b90f8d725da5a0de4de2dd6de62 upstream. This reverts commit 353748a359f1821ee934afc579cf04572406b420. It bypassed the linux-mtd review process and fixes the issue not as it should. Cc: Kees Cook Cc: Silvio Cesare Cc: stable@vger.kernel.org Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/journal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 2e169c2932d2..fb166e204441 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -1101,7 +1101,7 @@ static int recomp_data_node(struct ubifs_data_node *dn, int *new_len) int err, len, compr_type, out_len; out_len = le32_to_cpu(dn->size); - buf = kmalloc_array(out_len, WORST_COMPR_FACTOR, GFP_NOFS); + buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS); if (!buf) return -ENOMEM; From 37ca931c07ed22097bf4cbbe08ef26f9fe5383f5 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Tue, 12 Jun 2018 00:52:28 +0200 Subject: [PATCH 385/392] ubifs: Fix synced_i_size calculation for xattr inodes commit 59965593205fa4044850d35ee3557cf0b7edcd14 upstream. In ubifs_jnl_update() we sync parent and child inodes to the flash, in case of xattrs, the parent inode (AKA host inode) has a non-zero data_len. Therefore we need to adjust synced_i_size too. This issue was reported by ubifs self tests unter a xattr related work load. UBIFS error (ubi0:0 pid 1896): dbg_check_synced_i_size: ui_size is 4, synced_i_size is 0, but inode is clean UBIFS error (ubi0:0 pid 1896): dbg_check_synced_i_size: i_ino 65, i_mode 0x81a4, i_size 4 Cc: Fixes: 1e51764a3c2a ("UBIFS: add new flash file system") Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/journal.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index fb166e204441..4f496d354d6c 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -656,6 +656,11 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, spin_lock(&ui->ui_lock); ui->synced_i_size = ui->ui_size; spin_unlock(&ui->ui_lock); + if (xent) { + spin_lock(&host_ui->ui_lock); + host_ui->synced_i_size = host_ui->ui_size; + spin_unlock(&host_ui->ui_lock); + } mark_inode_clean(c, ui); mark_inode_clean(c, host_ui); return 0; From 6c4dcc23dd225272f1215dd8c415c3bfa1072908 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Mon, 11 Jun 2018 11:39:56 +0530 Subject: [PATCH 386/392] pwm: tiehrpwm: Fix disabling of output of PWMs commit 38dabd91ff0bde33352ca3cc65ef515599b77a05 upstream. pwm-tiehrpwm driver disables PWM output by putting it in low output state via active AQCSFRC register in ehrpwm_pwm_disable(). But, the AQCSFRC shadow register is not updated. Therefore, when shadow AQCSFRC register is re-enabled in ehrpwm_pwm_enable() (say to enable second PWM output), previous settings are lost as shadow register value is loaded into active register. This results in things like PWMA getting enabled automatically, when PWMB is enabled and vice versa. Fix this by updating AQCSFRC shadow register as well during ehrpwm_pwm_disable(). Fixes: 19891b20e7c2 ("pwm: pwm-tiehrpwm: PWM driver support for EHRPWM") Cc: stable@vger.kernel.org Signed-off-by: Vignesh R Signed-off-by: Thierry Reding Signed-off-by: Greg Kroah-Hartman --- drivers/pwm/pwm-tiehrpwm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index cb75133085a8..acc9987475f5 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -384,6 +384,8 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) aqcsfrc_mask = AQCSFRC_CSFA_MASK; } + /* Update shadow register first before modifying active register */ + ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); /* * Changes to immediate action on Action Qualifier. This puts * Action Qualifier control on PWM output from next TBCLK From 76391112d8abeadfa8641b38c2917170fea8520c Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 25 Jul 2018 15:41:54 +0200 Subject: [PATCH 387/392] fb: fix lost console when the user unplugs a USB adapter commit 8c5b044299951acd91e830a688dd920477ea1eda upstream. I have a USB display adapter using the udlfb driver and I use it on an ARM board that doesn't have any graphics card. When I plug the adapter in, the console is properly displayed, however when I unplug and re-plug the adapter, the console is not displayed and I can't access it until I reboot the board. The reason is this: When the adapter is unplugged, dlfb_usb_disconnect calls unlink_framebuffer, then it waits until the reference count drops to zero and then it deallocates the framebuffer. However, the console that is attached to the framebuffer device keeps the reference count non-zero, so the framebuffer device is never destroyed. When the USB adapter is plugged again, it creates a new device /dev/fb1 and the console is not attached to it. This patch fixes the bug by unbinding the console from unlink_framebuffer. The code to unbind the console is moved from do_unregister_framebuffer to a function unbind_console. When the console is unbound, the reference count drops to zero and the udlfb driver frees the framebuffer. When the adapter is plugged back, a new framebuffer is created and the console is attached to it. Signed-off-by: Mikulas Patocka Cc: Dave Airlie Cc: Bernie Thompson Cc: Ladislav Michl Cc: stable@vger.kernel.org [b.zolnierkie: preserve old behavior for do_unregister_framebuffer()] Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/core/fbmem.c | 38 +++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 0705d8883ede..8a29ec5992fd 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1687,12 +1687,12 @@ static int do_register_framebuffer(struct fb_info *fb_info) return 0; } -static int do_unregister_framebuffer(struct fb_info *fb_info) +static int unbind_console(struct fb_info *fb_info) { struct fb_event event; - int i, ret = 0; + int ret; + int i = fb_info->node; - i = fb_info->node; if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) return -EINVAL; @@ -1707,17 +1707,29 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) unlock_fb_info(fb_info); console_unlock(); + return ret; +} + +static int __unlink_framebuffer(struct fb_info *fb_info); + +static int do_unregister_framebuffer(struct fb_info *fb_info) +{ + struct fb_event event; + int ret; + + ret = unbind_console(fb_info); + if (ret) return -EINVAL; pm_vt_switch_unregister(fb_info->dev); - unlink_framebuffer(fb_info); + __unlink_framebuffer(fb_info); if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) kfree(fb_info->pixmap.addr); fb_destroy_modelist(&fb_info->modelist); - registered_fb[i] = NULL; + registered_fb[fb_info->node] = NULL; num_registered_fb--; fb_cleanup_device(fb_info); event.info = fb_info; @@ -1730,7 +1742,7 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) return 0; } -int unlink_framebuffer(struct fb_info *fb_info) +static int __unlink_framebuffer(struct fb_info *fb_info) { int i; @@ -1742,6 +1754,20 @@ int unlink_framebuffer(struct fb_info *fb_info) device_destroy(fb_class, MKDEV(FB_MAJOR, i)); fb_info->dev = NULL; } + + return 0; +} + +int unlink_framebuffer(struct fb_info *fb_info) +{ + int ret; + + ret = __unlink_framebuffer(fb_info); + if (ret) + return ret; + + unbind_console(fb_info); + return 0; } EXPORT_SYMBOL(unlink_framebuffer); From 6f2f65ee027b305db5dc2fe0e3ccb6f34766e17d Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 25 Jul 2018 15:41:55 +0200 Subject: [PATCH 388/392] udlfb: set optimal write delay commit bb24153a3f13dd0dbc1f8055ad97fe346d598f66 upstream. The default delay 5 jiffies is too much when the kernel is compiled with HZ=100 - it results in jumpy cursor in Xwindow. In order to find out the optimal delay, I benchmarked the driver on 1280x720x30fps video. I found out that with HZ=1000, 10ms is acceptable, but with HZ=250 or HZ=300, we need 4ms, so that the video is played without any frame skips. This patch changes the delay to this value. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Greg Kroah-Hartman --- include/video/udlfb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/video/udlfb.h b/include/video/udlfb.h index f9466fa54ba4..2ad9a6d37ff4 100644 --- a/include/video/udlfb.h +++ b/include/video/udlfb.h @@ -87,7 +87,7 @@ struct dlfb_data { #define MIN_RAW_PIX_BYTES 2 #define MIN_RAW_CMD_BYTES (RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES) -#define DL_DEFIO_WRITE_DELAY 5 /* fb_deferred_io.delay in jiffies */ +#define DL_DEFIO_WRITE_DELAY msecs_to_jiffies(HZ <= 300 ? 4 : 10) /* optimal value for 720p video */ #define DL_DEFIO_WRITE_DISABLE (HZ*60) /* "disable" with long delay */ /* remove these once align.h patch is taken into kernel */ From 054206a2797efd01809b8562b865db74112c4423 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 7 Jun 2018 13:43:48 +0200 Subject: [PATCH 389/392] getxattr: use correct xattr length commit 82c9a927bc5df6e06b72d206d24a9d10cced4eb5 upstream. When running in a container with a user namespace, if you call getxattr with name = "system.posix_acl_access" and size % 8 != 4, then getxattr silently skips the user namespace fixup that it normally does resulting in un-fixed-up data being returned. This is caused by posix_acl_fix_xattr_to_user() being passed the total buffer size and not the actual size of the xattr as returned by vfs_getxattr(). This commit passes the actual length of the xattr as returned by vfs_getxattr() down. A reproducer for the issue is: touch acl_posix setfacl -m user:0:rwx acl_posix and the compile: #define _GNU_SOURCE #include #include #include #include #include #include #include /* Run in user namespace with nsuid 0 mapped to uid != 0 on the host. */ int main(int argc, void **argv) { ssize_t ret1, ret2; char buf1[128], buf2[132]; int fret = EXIT_SUCCESS; char *file; if (argc < 2) { fprintf(stderr, "Please specify a file with " "\"system.posix_acl_access\" permissions set\n"); _exit(EXIT_FAILURE); } file = argv[1]; ret1 = getxattr(file, "system.posix_acl_access", buf1, sizeof(buf1)); if (ret1 < 0) { fprintf(stderr, "%s - Failed to retrieve " "\"system.posix_acl_access\" " "from \"%s\"\n", strerror(errno), file); _exit(EXIT_FAILURE); } ret2 = getxattr(file, "system.posix_acl_access", buf2, sizeof(buf2)); if (ret2 < 0) { fprintf(stderr, "%s - Failed to retrieve " "\"system.posix_acl_access\" " "from \"%s\"\n", strerror(errno), file); _exit(EXIT_FAILURE); } if (ret1 != ret2) { fprintf(stderr, "The value of \"system.posix_acl_" "access\" for file \"%s\" changed " "between two successive calls\n", file); _exit(EXIT_FAILURE); } for (ssize_t i = 0; i < ret2; i++) { if (buf1[i] == buf2[i]) continue; fprintf(stderr, "Unexpected different in byte %zd: " "%02x != %02x\n", i, buf1[i], buf2[i]); fret = EXIT_FAILURE; } if (fret == EXIT_SUCCESS) fprintf(stderr, "Test passed\n"); else fprintf(stderr, "Test failed\n"); _exit(fret); } and run: ./tester acl_posix On a non-fixed up kernel this should return something like: root@c1:/# ./t Unexpected different in byte 16: ffffffa0 != 00 Unexpected different in byte 17: ffffff86 != 00 Unexpected different in byte 18: 01 != 00 and on a fixed kernel: root@c1:~# ./t Test passed Cc: stable@vger.kernel.org Fixes: 2f6f0654ab61 ("userns: Convert vfs posix_acl support to use kuids and kgids") Link: https://bugzilla.kernel.org/show_bug.cgi?id=199945 Reported-by: Colin Watson Signed-off-by: Christian Brauner Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman Signed-off-by: Greg Kroah-Hartman --- fs/xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xattr.c b/fs/xattr.c index d536edbd377e..cfc6324cfd6e 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -455,7 +455,7 @@ getxattr(struct dentry *d, const char __user *name, void __user *value, if (error > 0) { if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) || (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)) - posix_acl_fix_xattr_to_user(kvalue, size); + posix_acl_fix_xattr_to_user(kvalue, error); if (size && copy_to_user(value, kvalue, error)) error = -EFAULT; } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { From b271f88e1a750763c96d7621e14b154114ea4dd3 Mon Sep 17 00:00:00 2001 From: Shan Hai Date: Thu, 23 Aug 2018 02:02:56 +0800 Subject: [PATCH 390/392] bcache: release dc->writeback_lock properly in bch_writeback_thread() commit 3943b040f11ed0cc6d4585fd286a623ca8634547 upstream. The writeback thread would exit with a lock held when the cache device is detached via sysfs interface, fix it by releasing the held lock before exiting the while-loop. Fixes: fadd94e05c02 (bcache: quit dc->writeback_thread when BCACHE_DEV_DETACHING is set) Signed-off-by: Shan Hai Signed-off-by: Coly Li Tested-by: Shenghui Wang Cc: stable@vger.kernel.org #4.17+ Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/writeback.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index 6e3fae202b11..fe19e5841bfc 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -462,8 +462,10 @@ static int bch_writeback_thread(void *arg) * data on cache. BCACHE_DEV_DETACHING flag is set in * bch_cached_dev_detach(). */ - if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)) + if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)) { + up_write(&dc->writeback_lock); break; + } } up_write(&dc->writeback_lock); From c0305995d3676c8f7764eb79a7f99de8d18c591a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 9 Sep 2018 20:07:57 +0200 Subject: [PATCH 391/392] Linux 3.18.122 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9a58c977c946..7f8ee7afb801 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 18 -SUBLEVEL = 121 +SUBLEVEL = 122 EXTRAVERSION = NAME = Diseased Newt From a10178b2a6d57d30da3b2aeefe2b2f1b562494b6 Mon Sep 17 00:00:00 2001 From: joshuous Date: Mon, 10 Sep 2018 13:45:40 +0000 Subject: [PATCH 392/392] Revert "UPSTREAM: sched/core: Allow putting thread_info into task_struct" Revert to prevent compilation conflicts in next Linux merge. This reverts commit 345119706e6bf4c7236e832f2cd39680d09624f6. Signed-off-by: joshuous --- include/linux/init_task.h | 9 --------- include/linux/sched.h | 36 ++---------------------------------- include/linux/thread_info.h | 15 --------------- init/Kconfig | 7 ------- init/init_task.c | 7 ++----- kernel/sched/sched.h | 4 ---- 6 files changed, 4 insertions(+), 74 deletions(-) diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 7693858c5583..16842b4e2056 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -15,8 +15,6 @@ #include #include -#include - #ifdef CONFIG_SMP # define INIT_PUSHABLE_TASKS(tsk) \ .pushable_tasks = PLIST_NODE_INIT(tsk.pushable_tasks, MAX_PRIO), @@ -175,19 +173,12 @@ extern struct task_group root_task_group; # define INIT_KASAN(tsk) #endif -#ifdef CONFIG_THREAD_INFO_IN_TASK -# define INIT_TASK_TI(tsk) .thread_info = INIT_THREAD_INFO(tsk), -#else -# define INIT_TASK_TI(tsk) -#endif - /* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) */ #define INIT_TASK(tsk) \ { \ - INIT_TASK_TI(tsk) \ .state = 0, \ .stack = &init_thread_info, \ .usage = ATOMIC_INIT(2), \ diff --git a/include/linux/sched.h b/include/linux/sched.h index 004733cd7d46..0e00bf883bea 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1457,13 +1457,6 @@ enum perf_event_task_context { }; struct task_struct { -#ifdef CONFIG_THREAD_INFO_IN_TASK - /* - * For reasons of header soup (see current_thread_info()), this - * must be the first element of task_struct. - */ - struct thread_info thread_info; -#endif volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ void *stack; atomic_t usage; @@ -1477,9 +1470,6 @@ struct task_struct { #ifdef CONFIG_SMP struct llist_node wake_entry; int on_cpu; -#ifdef CONFIG_THREAD_INFO_IN_TASK - unsigned int cpu; /* current CPU */ -#endif unsigned int wakee_flips; unsigned long wakee_flip_decay_ts; struct task_struct *last_wakee; @@ -2535,9 +2525,7 @@ void yield(void); extern struct exec_domain default_exec_domain; union thread_union { -#ifndef CONFIG_THREAD_INFO_IN_TASK struct thread_info thread_info; -#endif unsigned long stack[THREAD_SIZE/sizeof(long)]; }; @@ -2923,26 +2911,10 @@ static inline void threadgroup_lock(struct task_struct *tsk) {} static inline void threadgroup_unlock(struct task_struct *tsk) {} #endif -#ifdef CONFIG_THREAD_INFO_IN_TASK - -static inline struct thread_info *task_thread_info(struct task_struct *task) -{ - return &task->thread_info; -} -static inline void *task_stack_page(const struct task_struct *task) -{ - return task->stack; -} -#define setup_thread_stack(new,old) do { } while(0) -static inline unsigned long *end_of_stack(const struct task_struct *task) -{ - return task->stack; -} - -#elif !defined(__HAVE_THREAD_FUNCTIONS) +#ifndef __HAVE_THREAD_FUNCTIONS #define task_thread_info(task) ((struct thread_info *)(task)->stack) -#define task_stack_page(task) ((void *)(task)->stack) +#define task_stack_page(task) ((task)->stack) static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org) { @@ -3245,11 +3217,7 @@ static inline void ptrace_signal_wake_up(struct task_struct *t, bool resume) static inline unsigned int task_cpu(const struct task_struct *p) { -#ifdef CONFIG_THREAD_INFO_IN_TASK - return p->cpu; -#else return task_thread_info(p)->cpu; -#endif } static inline int task_node(const struct task_struct *p) diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 8784cebd0f51..4cf89517783a 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -13,21 +13,6 @@ struct timespec; struct compat_timespec; -#ifdef CONFIG_THREAD_INFO_IN_TASK -struct thread_info { - u32 flags; /* low level flags */ -}; - -#define INIT_THREAD_INFO(tsk) \ -{ \ - .flags = 0, \ -} -#endif - -#ifdef CONFIG_THREAD_INFO_IN_TASK -#define current_thread_info() ((struct thread_info *)current) -#endif - /* * System call restart block. */ diff --git a/init/Kconfig b/init/Kconfig index 7e042a043a62..ed4a0cf9845b 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -26,13 +26,6 @@ config IRQ_WORK config BUILDTIME_EXTABLE_SORT bool -config THREAD_INFO_IN_TASK - bool - help - Select this to move thread_info off the stack into task_struct. To - make this work, an arch will need to remove all thread_info fields - except flags and fix any runtime bugs. - menu "General setup" config BROKEN diff --git a/init/init_task.c b/init/init_task.c index 11f83be1fa79..ba0a7f362d9e 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -22,8 +22,5 @@ EXPORT_SYMBOL(init_task); * Initial thread structure. Alignment of this is handled by a special * linker map entry. */ -union thread_union init_thread_union __init_task_data = { -#ifndef CONFIG_THREAD_INFO_IN_TASK - INIT_THREAD_INFO(init_task) -#endif -}; +union thread_union init_thread_union __init_task_data = + { INIT_THREAD_INFO(init_task) }; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 9b08657c6915..7cdb1f5a388e 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1019,11 +1019,7 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) * per-task data have been completed by this moment. */ smp_wmb(); -#ifdef CONFIG_THREAD_INFO_IN_TASK - p->cpu = cpu; -#else task_thread_info(p)->cpu = cpu; -#endif p->wake_cpu = cpu; #endif }