diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2019-03-03 23:15:48 -0800 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2019-03-03 23:15:48 -0800 |
commit | f35418f1bc1d156799850dd2daa6efb617d503c7 (patch) | |
tree | ffead7b730a99fdc10cf69007276ad7f08576a33 | |
parent | 61c7c6c009fee9c1755760bddc2f4791774e7bc9 (diff) | |
parent | da1f3a51ebee37365ce2d7950356a3831aeb9faa (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.h | 5 | ||||
-rw-r--r-- | drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c | 146 | ||||
-rw-r--r-- | drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h | 2 | ||||
-rw-r--r-- | drivers/media/platform/msm/vidc/hfi_response_handler.c | 12 | ||||
-rw-r--r-- | drivers/media/platform/msm/vidc/vidc_hfi_api.h | 5 | ||||
-rw-r--r-- | drivers/media/platform/msm/vidc_3x/hfi_response_handler.c | 12 | ||||
-rw-r--r-- | drivers/media/platform/msm/vidc_3x/venus_hfi.c | 5 | ||||
-rw-r--r-- | drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h | 5 | ||||
-rw-r--r-- | drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 4 | ||||
-rw-r--r-- | drivers/power/supply/qcom/smb-lib.c | 1 | ||||
-rw-r--r-- | drivers/soc/qcom/glink_smem_native_xprt.c | 6 | ||||
-rw-r--r-- | include/linux/rwsem.h | 13 | ||||
-rw-r--r-- | kernel/Kconfig.locks | 4 | ||||
-rw-r--r-- | kernel/locking/rwsem-xadd.c | 31 | ||||
-rw-r--r-- | kernel/locking/rwsem.h | 68 | ||||
-rw-r--r-- | mm/memory.c | 2 |
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); |