aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2019-03-03 23:15:48 -0800
committerLinux Build Service Account <lnxbuild@localhost>2019-03-03 23:15:48 -0800
commitf35418f1bc1d156799850dd2daa6efb617d503c7 (patch)
treeffead7b730a99fdc10cf69007276ad7f08576a33
parent61c7c6c009fee9c1755760bddc2f4791774e7bc9 (diff)
parentda1f3a51ebee37365ce2d7950356a3831aeb9faa (diff)
Merge da1f3a51ebee37365ce2d7950356a3831aeb9faa on remote branchLA.UM.6.6.2.r1-06900-89xx.0
Change-Id: Ied40dbe080cd2f67a5d1bdbd9f2088ce8c8a90ef
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_10_0_0_hwreg.h5
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c146
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h2
-rw-r--r--drivers/media/platform/msm/vidc/hfi_response_handler.c12
-rw-r--r--drivers/media/platform/msm/vidc/vidc_hfi_api.h5
-rw-r--r--drivers/media/platform/msm/vidc_3x/hfi_response_handler.c12
-rw-r--r--drivers/media/platform/msm/vidc_3x/venus_hfi.c5
-rw-r--r--drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h5
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c4
-rw-r--r--drivers/power/supply/qcom/smb-lib.c1
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c6
-rw-r--r--include/linux/rwsem.h13
-rw-r--r--kernel/Kconfig.locks4
-rw-r--r--kernel/locking/rwsem-xadd.c31
-rw-r--r--kernel/locking/rwsem.h68
-rw-r--r--mm/memory.c2
16 files changed, 251 insertions, 70 deletions
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_10_0_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_10_0_0_hwreg.h
index 4c5ce02cf461..bcd8a9e2e707 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_10_0_0_hwreg.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_10_0_0_hwreg.h
@@ -28,6 +28,9 @@
#define mask_enable_clk_B 0x2
#define mask_ctrl_1_A 0x5
#define mask_ctrl_1_B 0xA
+#define mask_reset_A 0x1
+#define mask_reset_B 0x7
+#define mask_shutdown_A 0x3
#define mask_hs_freq_range 0x7F
#define mask_osc_freq_2 0xFF
#define mask_osc_freq_3 0xF00
@@ -56,8 +59,6 @@ static struct csiphy_reg_snps_parms_t csiphy_v10_0_0_snps = {
{0x58C, 0xFF}, /* mipi_csiphy_irq_mask_ctrl_lane_0 */
{0x5C8, 0xFF}, /* mipi_csiphy_irq_mask_ctrl_lane_clk_0 */
{0x20, 0x0}, /* mipi_csiphy_rx_sys_7_00 */
- {0x28, 0x43}, /* mipi_csiphy_rx_sys_9_00 */
- {0x380, 0x0}, /* mipi_csiphy_rx_startup_ovr_0_00 */
{0x384, 0x0}, /* mipi_csiphy_rx_startup_ovr_1_00 */
{0x388, 0xCC}, /* mipi_csiphy_rx_startup_ovr_2_00 */
{0x38C, 0x1}, /* mipi_csiphy_rx_startup_ovr_3_00 */
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 3968c7d80015..41939f83323e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -250,10 +250,13 @@ static int msm_csiphy_snps_2_lane_config(
csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
mipi_csiphy_rx_sys_7_00.addr + offset);
- msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_snps_reg.
- mipi_csiphy_rx_sys_9_00.data,
+ value = msm_camera_io_r(csiphybase +
+ csiphy_dev->ctrl_reg->csiphy_snps_reg.
+ mipi_csiphy_rx_clk_lane_6_00.addr + offset);
+ value |= SET_THE_BIT(7);
+ msm_camera_io_w(value,
csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
- mipi_csiphy_rx_sys_9_00.addr + offset);
+ mipi_csiphy_rx_clk_lane_6_00.addr + offset);
msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_snps_reg.
mipi_csiphy_rx_startup_ovr_4_00.data,
@@ -315,7 +318,7 @@ static int msm_csiphy_snps_lane_config(
uint16_t lane_mask = 0;
void __iomem *csiphybase;
enum snps_csiphy_mode mode = INVALID_MODE;
- uint32_t value, num_tries, num_lanes, offset;
+ uint32_t value, num_tries, num_lanes, offset = SNPS_INTERPHY_OFFSET;
uint32_t clk_mux_reg = 0;
csiphybase = csiphy_dev->base;
@@ -495,17 +498,6 @@ static int msm_csiphy_snps_lane_config(
value = msm_camera_io_r(csiphybase +
csiphy_dev->ctrl_reg->csiphy_snps_reg.
- mipi_csiphy_rx_startup_ovr_0_00.addr +
- SNPS_INTERPHY_OFFSET);
- value |= SET_THE_BIT(0);
- value |= SET_THE_BIT(1);
- msm_camera_io_w(value,
- csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
- mipi_csiphy_rx_startup_ovr_0_00.addr +
- SNPS_INTERPHY_OFFSET);
-
- value = msm_camera_io_r(csiphybase +
- csiphy_dev->ctrl_reg->csiphy_snps_reg.
mipi_csiphy_rx_startup_ovr_1_00.addr +
SNPS_INTERPHY_OFFSET);
value &= ~(SET_THE_BIT(0));
@@ -519,6 +511,7 @@ static int msm_csiphy_snps_lane_config(
csiphy_dev->ctrl_reg->csiphy_snps_reg.
mipi_csiphy_rx_clk_lane_6_00.addr);
value |= SET_THE_BIT(2);
+ value &= ~(SET_THE_BIT(7));
msm_camera_io_w(value,
csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
mipi_csiphy_rx_clk_lane_6_00.addr);
@@ -528,7 +521,7 @@ static int msm_csiphy_snps_lane_config(
mipi_csiphy_rx_clk_lane_6_00.addr +
SNPS_INTERPHY_OFFSET);
value |= SET_THE_BIT(3);
- value |= SET_THE_BIT(7);
+ value &= ~(SET_THE_BIT(7));
value &= ~(SET_THE_BIT(2));
msm_camera_io_w(value,
csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
@@ -590,36 +583,109 @@ static int msm_csiphy_snps_lane_config(
csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
mipi_csiphy_enable_clk.addr);
- value = 0x0;
- if (mode == AGGREGATE_MODE || mode == TWO_LANE_PHY_A)
- value |= mask_ctrl_1_A;
- if (mode == AGGREGATE_MODE || mode == TWO_LANE_PHY_B)
- value |= mask_ctrl_1_B;
- msm_camera_io_w(value,
+ if (mode == TWO_LANE_PHY_A) {
+ msm_camera_io_w(mask_reset_A,
csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
mipi_csiphy_ctrl_1.addr);
- if (mode == AGGREGATE_MODE || mode == TWO_LANE_PHY_A)
- offset = 0x0;
- else
- offset = SNPS_INTERPHY_OFFSET;
+ msm_camera_io_w(mask_ctrl_1_A,
+ csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
+ mipi_csiphy_ctrl_1.addr);
- value = 0x0;
- num_tries = 0;
+ value = 0x0;
+ num_tries = 0;
+
+ do {
+ num_tries++;
+ value = msm_camera_io_r(csiphybase +
+ csiphy_dev->ctrl_reg->csiphy_snps_reg.
+ mipi_csiphy_rx_startup_obs_2_00.addr);
+ if ((value | SET_THE_BIT(4)) == value)
+ break;
+ usleep_range(100, 150);
+ } while (num_tries < 6);
+ if ((value | SET_THE_BIT(4)) != value) {
+ pr_err("%s: SNPS phy config failed\n", __func__);
+ return -EINVAL;
+ }
+ }
- do {
- num_tries++;
- value = msm_camera_io_r(csiphybase +
- csiphy_dev->ctrl_reg->csiphy_snps_reg.
- mipi_csiphy_rx_startup_obs_2_00.addr + offset);
- if ((value | SET_THE_BIT(4)) == value)
- break;
- usleep_range(100, 150);
- } while (num_tries < 6);
+ if (mode == TWO_LANE_PHY_B) {
+ msm_camera_io_w(mask_reset_B,
+ csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
+ mipi_csiphy_ctrl_1.addr);
- if ((value | SET_THE_BIT(4)) != value) {
- pr_err("%s: SNPS phy config failed\n", __func__);
- return -EINVAL;
+ msm_camera_io_w(mask_ctrl_1_A|mask_ctrl_1_B,
+ csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
+ mipi_csiphy_ctrl_1.addr);
+
+ value = 0x0;
+ num_tries = 0;
+
+ do {
+ num_tries++;
+ value = msm_camera_io_r(csiphybase +
+ csiphy_dev->ctrl_reg->csiphy_snps_reg.
+ mipi_csiphy_rx_startup_obs_2_00.addr + offset);
+ if ((value | SET_THE_BIT(4)) == value)
+ break;
+ usleep_range(100, 150);
+ } while (num_tries < 6);
+
+ if ((value | SET_THE_BIT(4)) != value) {
+ pr_err("%s: SNPS phy config failed\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ if (mode == AGGREGATE_MODE) {
+ msm_camera_io_w(mask_shutdown_A,
+ csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
+ mipi_csiphy_ctrl_1.addr);
+
+ msm_camera_io_w(mask_reset_B,
+ csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
+ mipi_csiphy_ctrl_1.addr);
+
+ value = 0x0;
+ num_tries = 0;
+
+ do {
+ num_tries++;
+ value = msm_camera_io_r(csiphybase +
+ csiphy_dev->ctrl_reg->csiphy_snps_reg.
+ mipi_csiphy_rx_startup_obs_2_00.addr);
+ if ((value | SET_THE_BIT(4)) == value)
+ break;
+ usleep_range(100, 150);
+ } while (num_tries < 6);
+
+ if ((value | SET_THE_BIT(4)) != value) {
+ pr_err("%s: SNPS phy config failed\n", __func__);
+ return -EINVAL;
+ }
+
+ msm_camera_io_w(mask_ctrl_1_A|mask_ctrl_1_B,
+ csiphybase + csiphy_dev->ctrl_reg->csiphy_snps_reg.
+ mipi_csiphy_ctrl_1.addr);
+
+ value = 0x0;
+ num_tries = 0;
+
+ do {
+ num_tries++;
+ value = msm_camera_io_r(csiphybase +
+ csiphy_dev->ctrl_reg->csiphy_snps_reg.
+ mipi_csiphy_rx_startup_obs_2_00.addr + offset);
+ if ((value | SET_THE_BIT(4)) == value)
+ break;
+ usleep_range(100, 150);
+ } while (num_tries < 6);
+
+ if ((value | SET_THE_BIT(4)) != value) {
+ pr_err("%s: SNPS phy config failed\n", __func__);
+ return -EINVAL;
+ }
}
msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_snps_reg.
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
index 6fc084c5fde0..dade2e377038 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
@@ -83,8 +83,6 @@ struct csiphy_reg_snps_parms_t {
struct csiphy_reg_t mipi_csiphy_irq_mask_ctrl_lane_0;
struct csiphy_reg_t mipi_csiphy_irq_mask_ctrl_lane_clk_0;
struct csiphy_reg_t mipi_csiphy_rx_sys_7_00;
- struct csiphy_reg_t mipi_csiphy_rx_sys_9_00;
- struct csiphy_reg_t mipi_csiphy_rx_startup_ovr_0_00;
struct csiphy_reg_t mipi_csiphy_rx_startup_ovr_1_00;
struct csiphy_reg_t mipi_csiphy_rx_startup_ovr_2_00;
struct csiphy_reg_t mipi_csiphy_rx_startup_ovr_3_00;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 0881a30509ec..92deba17745f 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, 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
@@ -751,6 +751,11 @@ static int hfi_fill_codec_info(u8 *data_ptr,
vidc_get_hal_codec((1 << i) & codecs);
capability->domain =
vidc_get_hal_domain(HFI_VIDEO_DOMAIN_DECODER);
+ if (codec_count == VIDC_MAX_DECODE_SESSIONS) {
+ dprintk(VIDC_ERR,
+ "Max supported decoder sessions reached");
+ break;
+ }
}
}
codecs = sys_init_done->enc_codec_supported;
@@ -762,6 +767,11 @@ static int hfi_fill_codec_info(u8 *data_ptr,
vidc_get_hal_codec((1 << i) & codecs);
capability->domain =
vidc_get_hal_domain(HFI_VIDEO_DOMAIN_ENCODER);
+ if (codec_count == VIDC_MAX_SESSIONS) {
+ dprintk(VIDC_ERR,
+ "Max supported sessions reached");
+ break;
+ }
}
}
sys_init_done->codec_count = codec_count;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 2d9f3f1811c5..ed1588c9990e 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, 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
@@ -66,6 +66,9 @@
/* 16 encoder and 16 decoder sessions */
#define VIDC_MAX_SESSIONS 32
+#define VIDC_MAX_DECODE_SESSIONS 16
+#define VIDC_MAX_ENCODE_SESSIONS 16
+
enum vidc_status {
VIDC_ERR_NONE = 0x0,
diff --git a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
index ca9edc8bebd1..8eaf1fd192af 100644
--- a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, 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
@@ -608,6 +608,11 @@ static int hfi_fill_codec_info(u8 *data_ptr,
vidc_get_hal_codec((1 << i) & codecs);
capability->domain =
vidc_get_hal_domain(HFI_VIDEO_DOMAIN_DECODER);
+ if (codec_count == VIDC_MAX_DECODE_SESSIONS) {
+ dprintk(VIDC_ERR,
+ "Max supported decoder sessions reached\n");
+ break;
+ }
}
}
codecs = sys_init_done->enc_codec_supported;
@@ -619,6 +624,11 @@ static int hfi_fill_codec_info(u8 *data_ptr,
vidc_get_hal_codec((1 << i) & codecs);
capability->domain =
vidc_get_hal_domain(HFI_VIDEO_DOMAIN_ENCODER);
+ if (codec_count == VIDC_MAX_SESSIONS) {
+ dprintk(VIDC_ERR,
+ "Max supported sessions reached\n");
+ break;
+ }
}
}
sys_init_done->codec_count = codec_count;
diff --git a/drivers/media/platform/msm/vidc_3x/venus_hfi.c b/drivers/media/platform/msm/vidc_3x/venus_hfi.c
index 1bd6ae8959cf..0c3ed26cb090 100644
--- a/drivers/media/platform/msm/vidc_3x/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc_3x/venus_hfi.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, 2018-2019 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
@@ -3428,7 +3429,7 @@ static int __response_handler(struct venus_hfi_device *device)
packets = device->response_pkt;
- raw_packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_TEMPORARY);
+ raw_packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_KERNEL);
if (!raw_packet || !packets) {
dprintk(VIDC_ERR, "%s: Failed to allocate memory\n", __func__);
kfree(raw_packet);
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h
index 1a25a58f1032..4d7379bd594d 100644
--- a/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, 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
@@ -66,6 +66,9 @@
/* 16 encoder and 16 decoder sessions */
#define VIDC_MAX_SESSIONS 32
+#define VIDC_MAX_DECODE_SESSIONS 16
+#define VIDC_MAX_ENCODE_SESSIONS 16
+
enum vidc_status {
VIDC_ERR_NONE = 0x0,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index d2b3b4e38f2f..3cc0c1012b98 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, 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
@@ -4318,7 +4318,7 @@ static int ipa3_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res)
return -EINVAL;
}
- if (iface < 0 || iface > IPA_VLAN_IF_MAX) {
+ if (iface < 0 || iface >= IPA_VLAN_IF_MAX) {
IPAERR("invalid iface %d\n", iface);
return -EINVAL;
}
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index b8350aba70a1..5d9766ed1040 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -2853,6 +2853,7 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
chg->pd_active = pd_active;
if (chg->pd_active) {
+ chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index da122fc82e73..d8e5d9fb38a5 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2019, 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
@@ -459,6 +459,8 @@ static int fifo_read(struct edge_info *einfo, void *_data, int len)
uint32_t fifo_size = einfo->rx_fifo_size;
uint32_t n;
+ if (read_index >= fifo_size || write_index >= fifo_size)
+ return 0;
while (len) {
ptr = einfo->rx_fifo + read_index;
if (read_index <= write_index)
@@ -505,6 +507,8 @@ static int fifo_write_body(struct edge_info *einfo, const void *_data,
uint32_t fifo_size = einfo->tx_fifo_size;
uint32_t n;
+ if (read_index >= fifo_size || *write_index >= fifo_size)
+ return 0;
while (len) {
ptr = einfo->tx_fifo + *write_index;
if (*write_index < read_index) {
diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
index dd1d14250340..38a66fdd2615 100644
--- a/include/linux/rwsem.h
+++ b/include/linux/rwsem.h
@@ -41,6 +41,10 @@ struct rw_semaphore {
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
+#ifdef CONFIG_RWSEM_PRIO_AWARE
+ /* count for waiters preempt to queue in wait list */
+ long m_count;
+#endif
};
extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
@@ -75,12 +79,19 @@ static inline int rwsem_is_locked(struct rw_semaphore *sem)
#define __RWSEM_OPT_INIT(lockname)
#endif
+#ifdef CONFIG_RWSEM_PRIO_AWARE
+#define __RWSEM_PRIO_AWARE_INIT(lockname) .m_count = 0
+#else
+#define __RWSEM_PRIO_AWARE_INIT(lockname)
+#endif
+
#define __RWSEM_INITIALIZER(name) \
{ __RWSEM_INIT_COUNT(name), \
.wait_list = LIST_HEAD_INIT((name).wait_list), \
.wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \
__RWSEM_OPT_INIT(name) \
- __RWSEM_DEP_MAP_INIT(name) }
+ __RWSEM_DEP_MAP_INIT(name), \
+ __RWSEM_PRIO_AWARE_INIT(name) }
#define DECLARE_RWSEM(name) \
struct rw_semaphore name = __RWSEM_INITIALIZER(name)
diff --git a/kernel/Kconfig.locks b/kernel/Kconfig.locks
index ebdb0043203a..2a31a580ac44 100644
--- a/kernel/Kconfig.locks
+++ b/kernel/Kconfig.locks
@@ -248,3 +248,7 @@ config ARCH_USE_QUEUED_RWLOCKS
config QUEUED_RWLOCKS
def_bool y if ARCH_USE_QUEUED_RWLOCKS
depends on SMP
+
+config RWSEM_PRIO_AWARE
+ def_bool y
+ depends on RWSEM_XCHGADD_ALGORITHM
diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c
index a4112dfcd0fb..15be517243f0 100644
--- a/kernel/locking/rwsem-xadd.c
+++ b/kernel/locking/rwsem-xadd.c
@@ -87,21 +87,13 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name,
sem->owner = NULL;
osq_lock_init(&sem->osq);
#endif
+#ifdef CONFIG_RWSEM_PRIO_AWARE
+ sem->m_count = 0;
+#endif
}
EXPORT_SYMBOL(__init_rwsem);
-enum rwsem_waiter_type {
- RWSEM_WAITING_FOR_WRITE,
- RWSEM_WAITING_FOR_READ
-};
-
-struct rwsem_waiter {
- struct list_head list;
- struct task_struct *task;
- enum rwsem_waiter_type type;
-};
-
enum rwsem_wake_type {
RWSEM_WAKE_ANY, /* Wake whatever's at head of wait list */
RWSEM_WAKE_READERS, /* Wake readers only */
@@ -226,6 +218,7 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)
struct rwsem_waiter waiter;
struct task_struct *tsk = current;
WAKE_Q(wake_q);
+ bool is_first_waiter = false;
waiter.task = tsk;
waiter.type = RWSEM_WAITING_FOR_READ;
@@ -233,7 +226,9 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)
raw_spin_lock_irq(&sem->wait_lock);
if (list_empty(&sem->wait_list))
adjustment += RWSEM_WAITING_BIAS;
- list_add_tail(&waiter.list, &sem->wait_list);
+
+ /* is_first_waiter == true means we are first in the queue */
+ is_first_waiter = rwsem_list_add_per_prio(&waiter, sem);
/* we're now waiting on the lock, but no longer actively locking */
count = atomic_long_add_return(adjustment, &sem->count);
@@ -246,7 +241,8 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)
*/
if (count == RWSEM_WAITING_BIAS ||
(count > RWSEM_WAITING_BIAS &&
- adjustment != -RWSEM_ACTIVE_READ_BIAS))
+ (adjustment != -RWSEM_ACTIVE_READ_BIAS ||
+ is_first_waiter)))
__rwsem_mark_wake(sem, RWSEM_WAKE_ANY, &wake_q);
raw_spin_unlock_irq(&sem->wait_lock);
@@ -462,6 +458,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state)
struct rwsem_waiter waiter;
struct rw_semaphore *ret = sem;
WAKE_Q(wake_q);
+ bool is_first_waiter = false;
/* undo write bias from down_write operation, stop active locking */
count = atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS, &sem->count);
@@ -483,7 +480,11 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state)
if (list_empty(&sem->wait_list))
waiting = false;
- list_add_tail(&waiter.list, &sem->wait_list);
+ /*
+ * is_first_waiter == true means we are first in the queue,
+ * so there is no read locks that were queued ahead of us.
+ */
+ is_first_waiter = rwsem_list_add_per_prio(&waiter, sem);
/* we're now waiting on the lock, but no longer actively locking */
if (waiting) {
@@ -494,7 +495,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state)
* no active writers, the lock must be read owned; so we try to
* wake any read locks that were queued ahead of us.
*/
- if (count > RWSEM_WAITING_BIAS) {
+ if (!is_first_waiter && count > RWSEM_WAITING_BIAS) {
WAKE_Q(wake_q);
__rwsem_mark_wake(sem, RWSEM_WAKE_READERS, &wake_q);
diff --git a/kernel/locking/rwsem.h b/kernel/locking/rwsem.h
index a699f4048ba1..b60c84222bba 100644
--- a/kernel/locking/rwsem.h
+++ b/kernel/locking/rwsem.h
@@ -15,6 +15,17 @@
*/
#define RWSEM_READER_OWNED ((struct task_struct *)1UL)
+enum rwsem_waiter_type {
+ RWSEM_WAITING_FOR_WRITE,
+ RWSEM_WAITING_FOR_READ
+};
+
+struct rwsem_waiter {
+ struct list_head list;
+ struct task_struct *task;
+ enum rwsem_waiter_type type;
+};
+
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
/*
* All writes to owner are protected by WRITE_ONCE() to make sure that
@@ -66,3 +77,60 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem)
{
}
#endif
+
+#ifdef CONFIG_RWSEM_PRIO_AWARE
+
+#define RWSEM_MAX_PREEMPT_ALLOWED 3000
+
+/*
+ * Return true if current waiter is added in the front of the rwsem wait list.
+ */
+static inline bool rwsem_list_add_per_prio(struct rwsem_waiter *waiter_in,
+ struct rw_semaphore *sem)
+{
+ struct list_head *pos;
+ struct list_head *head;
+ struct rwsem_waiter *waiter = NULL;
+
+ pos = head = &sem->wait_list;
+ /*
+ * Rules for task prio aware rwsem wait list queueing:
+ * 1: Only try to preempt waiters with which task priority
+ * which is higher than DEFAULT_PRIO.
+ * 2: To avoid starvation, add count to record
+ * how many high priority waiters preempt to queue in wait
+ * list.
+ * If preempt count is exceed RWSEM_MAX_PREEMPT_ALLOWED,
+ * use simple fifo until wait list is empty.
+ */
+ if (list_empty(head)) {
+ list_add_tail(&waiter_in->list, head);
+ sem->m_count = 0;
+ return true;
+ }
+
+ if (waiter_in->task->prio < DEFAULT_PRIO
+ && sem->m_count < RWSEM_MAX_PREEMPT_ALLOWED) {
+
+ list_for_each(pos, head) {
+ waiter = list_entry(pos, struct rwsem_waiter, list);
+ if (waiter->task->prio > waiter_in->task->prio) {
+ list_add(&waiter_in->list, pos->prev);
+ sem->m_count++;
+ return &waiter_in->list == head->next;
+ }
+ }
+ }
+
+ list_add_tail(&waiter_in->list, head);
+
+ return false;
+}
+#else
+static inline bool rwsem_list_add_per_prio(struct rwsem_waiter *waiter_in,
+ struct rw_semaphore *sem)
+{
+ list_add_tail(&waiter_in->list, &sem->wait_list);
+ return false;
+}
+#endif
diff --git a/mm/memory.c b/mm/memory.c
index 82d200013329..f35934f79f79 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1946,7 +1946,7 @@ int apply_to_page_range(struct mm_struct *mm, unsigned long addr,
unsigned long end = addr + size;
int err;
- if (WARN_ON(addr >= end))
+ if (WARN_ON(addr >= end - 1))
return -EINVAL;
pgd = pgd_offset(mm, addr);