Merge 91a7f066e1 on remote branch

Change-Id: I826320b3aa563dabb7d6bfa1b5bc2f4ee5cd2b76
This commit is contained in:
Linux Build Service Account 2021-06-23 05:14:20 -07:00
commit 12398f32a8
79 changed files with 4501 additions and 1649 deletions

View file

@ -1 +1 @@
LTS_5.4.86_ccdcd307cf7e
LTS_5.4.86_7d99cf8c84a7

File diff suppressed because it is too large Load diff

View file

@ -92,6 +92,7 @@
devm_phy_get
devm_pinctrl_register
devm_platform_ioremap_resource
devm_regmap_field_alloc
__devm_regmap_init_mmio_clk
devm_regulator_bulk_get
devm_regulator_get
@ -213,6 +214,7 @@
irq_set_irq_wake
irq_to_desc
jiffies
jiffies_to_usecs
kfree
kfree_skb
kimage_vaddr
@ -251,6 +253,8 @@
__netdev_alloc_skb
netif_napi_add
netif_napi_del
nvmem_cell_get
nvmem_cell_put
nvmem_cell_read
of_address_to_resource
of_alias_get_id
@ -368,6 +372,7 @@
__register_rpmsg_driver
regmap_bulk_read
regmap_bulk_write
regmap_field_read
regmap_read
regmap_update_bits_base
regmap_write
@ -1048,8 +1053,6 @@
no_llseek
nsecs_to_jiffies
ns_to_timespec
nvmem_cell_get
nvmem_cell_put
of_device_is_available
of_dma_configure
of_drm_find_bridge
@ -1227,10 +1230,8 @@
of_irq_get
# required by qcom_hwspinlock.ko
devm_regmap_field_alloc
hwspin_lock_register
hwspin_lock_unregister
regmap_field_read
regmap_field_update_bits_base
# required by qcom_q6v5.ko
@ -1252,7 +1253,6 @@
__memcpy_toio
# required by qcom_spmi-regulator.ko
jiffies_to_usecs
regulator_disable_regmap
regulator_enable_regmap
regulator_is_enabled_regmap
@ -1263,6 +1263,10 @@
rproc_get_by_child
try_wait_for_completion
# required by qcom_tsens.ko
devm_thermal_zone_of_sensor_register
thermal_zone_get_slope
# required by qmi_helpers.ko
init_net
kernel_getsockname

View file

@ -1462,6 +1462,7 @@
static_key_initialized
static_key_slow_dec
static_key_slow_inc
stpcpy
strcasecmp
strcat
strchr

View file

@ -1103,9 +1103,11 @@
gpiochip_generic_free
gpiochip_generic_request
gpiochip_get_data
gpiochip_irqchip_add_key
gpiochip_line_is_valid
gpiochip_lock_as_irq
gpiochip_remove
gpiochip_set_nested_irqchip
gpiochip_unlock_as_irq
gpiod_direction_input
gpiod_direction_output

View file

@ -45,10 +45,12 @@
backlight_device_unregister
bin2hex
__bitmap_clear
bitmap_find_free_region
bitmap_find_next_zero_area_off
bitmap_free
bitmap_parselist
bitmap_print_to_pagebuf
bitmap_release_region
__bitmap_set
__bitmap_subset
bitmap_zalloc
@ -1803,6 +1805,7 @@
__pm_runtime_use_autosuspend
__pm_stay_awake
pm_stay_awake
pm_system_cancel_wakeup
pm_system_wakeup
pm_wakeup_dev_event
pm_wakeup_ws_event
@ -2024,6 +2027,7 @@
rpmsg_set_signals
rpmsg_trysend
rpmsg_unregister_device
rtc_add_group
rtc_class_close
rtc_class_open
rtc_read_time

View file

@ -430,6 +430,7 @@ CONFIG_INCREMENTAL_FS=y
CONFIG_QFMT_V2=y
# CONFIG_QFMT_V1 is not set
CONFIG_MSM_ADSPRPC=y
CONFIG_MSM_RDBG=m
CONFIG_QSEECOM=y
CONFIG_USB_CONFIGFS_F_ACC=y
CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y

View file

@ -890,3 +890,5 @@ CONFIG_QTI_SYSTEM_PM_RPM=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_STM_PROTO_BASIC=y
CONFIG_QTI_ADC_TM=y
CONFIG_PANIC_ON_SCHED_BUG=y
CONFIG_PANIC_ON_RT_THROTTLING=y

View file

@ -64,6 +64,62 @@ CONFIG_INTERCONNECT_TEST=y
CONFIG_INTERCONNECT_QCOM=y
CONFIG_DEBUG_FS=y
CONFIG_ARCH_SDXNIGHTJAR=y
CONFIG_ETHERNET=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
# CONFIG_NET_VENDOR_AGERE is not set
# CONFIG_NET_VENDOR_ALACRITECH is not set
# CONFIG_NET_VENDOR_ALTEON is not set
# CONFIG_ALTERA_TSE is not set
# CONFIG_NET_VENDOR_AMAZON is not set
# CONFIG_NET_VENDOR_AMD is not set
# CONFIG_NET_VENDOR_AQUANTIA is not set
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ATHEROS=y
# CONFIG_ATL2 is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
# CONFIG_ATL1C is not set
# CONFIG_ALX is not set
# CONFIG_NET_VENDOR_AURORA is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_BROCADE is not set
# CONFIG_NET_VENDOR_CADENCE is not set
# CONFIG_NET_VENDOR_CAVIUM is not set
# CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_CIRRUS is not set
# CONFIG_NET_VENDOR_CISCO is not set
# CONFIG_NET_VENDOR_CORTINA is not set
# CONFIG_DM9000 is not set
# CONFIG_DNET is not set
# CONFIG_NET_VENDOR_DEC is not set
# CONFIG_NET_VENDOR_DLINK is not set
# CONFIG_NET_VENDOR_EMULEX is not set
# CONFIG_NET_VENDOR_EZCHIP is not set
# CONFIG_NET_VENDOR_FARADAY is not set
# CONFIG_NET_VENDOR_GOOGLE is not set
# CONFIG_NET_VENDOR_HISILICON is not set
# CONFIG_NET_VENDOR_HP is not set
# CONFIG_NET_VENDOR_HUAWEI is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_JME is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MELLANOX is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_MICROCHIP is not set
# CONFIG_NET_VENDOR_MICROSEMI is not set
# CONFIG_NET_VENDOR_MYRI is not set
# CONFIG_FEALNX is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_NETERION is not set
# CONFIG_NET_VENDOR_NETRONOME is not set
# CONFIG_NET_VENDOR_NI is not set
# CONFIG_NET_VENDOR_NVIDIA is not set
# CONFIG_NET_VENDOR_OKI is not set
# CONFIG_ETHOC is not set
# CONFIG_NET_VENDOR_PACKET_ENGINES is not set
# CONFIG_NET_VENDOR_PENSANDO is not set
# CONFIG_NET_VENDOR_QLOGIC is not set
CONFIG_PINCTRL_SDXNIGHTJAR=y
# CONFIG_ARCH_SDXLEMUR is not set
# CONFIG_PINCTRL_SDXLEMUR is not set
@ -926,3 +982,19 @@ CONFIG_PCIEPORTBUS=y
CONFIG_PCIEAER=y
CONFIG_PCI_QTI=y
CONFIG_PCIEASPM_POWER_SUPERSAVE=y
# CONFIG_WLAN_VENDOR_ADMTEK is not set
# CONFIG_WLAN_VENDOR_ATH is not set
# CONFIG_WLAN_VENDOR_ATMEL is not set
# CONFIG_WLAN_VENDOR_BROADCOM is not set
# CONFIG_WLAN_VENDOR_CISCO is not set
# CONFIG_WLAN_VENDOR_INTEL is not set
# CONFIG_WLAN_VENDOR_INTERSIL is not set
# CONFIG_WLAN_VENDOR_MARVELL is not set
# CONFIG_WLAN_VENDOR_MEDIATEK is not set
# CONFIG_WLAN_VENDOR_RALINK is not set
# CONFIG_WLAN_VENDOR_REALTEK is not set
# CONFIG_WLAN_VENDOR_RSI is not set
# CONFIG_WLAN_VENDOR_ST is not set
# CONFIG_WLAN_VENDOR_TI is not set
# CONFIG_WLAN_VENDOR_ZYDAS is not set
# CONFIG_WLAN_VENDOR_QUANTENNA is not set

View file

@ -12,6 +12,7 @@ CONFIG_PINCTRL_QCOM_SPMI_PMIC=m
CONFIG_PINCTRL_SDM845=m
CONFIG_POWER_RESET_QCOM_PON=m
CONFIG_SYSCON_REBOOT_MODE=m
CONFIG_QCOM_TSENS=m
CONFIG_QCOM_WDT=m
CONFIG_PM8916_WATCHDOG=m
CONFIG_MFD_SPMI_PMIC=m

View file

@ -239,3 +239,4 @@ CONFIG_SM_GCC_BLAIR=m
CONFIG_SM_GPUCC_BLAIR=m
CONFIG_SM_DISPCC_BLAIR=m
CONFIG_SM_DEBUGCC_BLAIR=m
CONFIG_QCOM_CX_IPEAK=m

View file

@ -198,6 +198,7 @@ CONFIG_VIDEOBUF2_VMALLOC=m
CONFIG_SLIMBUS_MSM_NGD=m
CONFIG_QRTR_HAVEN=m
CONFIG_QCOM_CDSP_RM=m
CONFIG_QCOM_SYSMON_SUBSYSTEM_STATS=m
CONFIG_QCOM_PDC=m
CONFIG_HEADER_TEST=y
CONFIG_HEADERS_INSTALL=y

View file

@ -630,7 +630,10 @@ static struct elevator_type *elevator_get_default(struct request_queue *q)
{
if (q->nr_hw_queues != 1)
return NULL;
#if defined(CONFIG_SDC_QTI) || defined(CONFIG_SCSI_UFSHCD_QTI)
if (IS_ENABLED(CONFIG_IOSCHED_BFQ))
return elevator_get(q, "bfq", false);
#endif
return elevator_get(q, "mq-deadline", false);
}

View file

@ -1373,7 +1373,7 @@ static void device_links_purge(struct device *dev)
return;
mutex_lock(&wfs_lock);
list_del(&dev->links.needs_suppliers);
list_del_init(&dev->links.needs_suppliers);
mutex_unlock(&wfs_lock);
/*

View file

@ -925,6 +925,7 @@ void pm_system_cancel_wakeup(void)
{
atomic_dec_if_positive(&pm_abort_suspend);
}
EXPORT_SYMBOL_GPL(pm_system_cancel_wakeup);
void pm_wakeup_clear(bool reset)
{

View file

@ -276,6 +276,12 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
#define LUCID_EVO_PLL_L_VAL_MASK GENMASK(15, 0)
#define LUCID_EVO_PLL_CAL_L_VAL_MASK GENMASK(31, 16)
/*
* The lucid_5lpe CPU PLL on SDX targets overloaded this field. Reading it
* returns PCAL_DONE and writing it asserts the latch.
*/
#define LUCID_5LPE_SDX_CPU_LATCH_INPUT LUCID_5LPE_PCAL_DONE
/* ZONDA PLL specific offsets */
#define ZONDA_PLL_OUT_MASK 0xF
#define ZONDA_STAY_IN_CFA BIT(16)
@ -3190,6 +3196,61 @@ static int alpha_pll_lucid_5lpe_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
static int alpha_pll_lucid_5lpe_sdx_cpu_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long prate)
{
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
unsigned long rrate;
u32 regval, l;
u64 a;
int ret;
rrate = alpha_pll_round_rate(rate, prate, &l, &a, ALPHA_REG_16BIT_WIDTH);
/*
* Due to a limited number of bits for fractional rate programming, the
* rounded up rate could be marginally higher than the requested rate.
*/
if (rrate > (rate + PLL_OUT_RATE_MARGIN) || rrate < rate) {
pr_err("Call set rate on the PLL with rounded rates!\n");
return -EINVAL;
}
regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
/* Latch the PLL input */
ret = regmap_write_bits(pll->clkr.regmap, PLL_MODE(pll),
LUCID_5LPE_SDX_CPU_LATCH_INPUT,
LUCID_5LPE_SDX_CPU_LATCH_INPUT);
if (ret)
return ret;
/* Wait for 2 reference cycles before checking the ACK bit. */
udelay(1);
regmap_read(pll->clkr.regmap, PLL_MODE(pll), &regval);
if (!(regval & LUCID_5LPE_ALPHA_PLL_ACK_LATCH)) {
WARN_CLK(&pll->clkr.hw, 1,
"PLL latch failed. Output may be unstable!\n");
return -EINVAL;
}
/* Return the latch input to 0 */
ret = regmap_write_bits(pll->clkr.regmap, PLL_MODE(pll),
LUCID_5LPE_SDX_CPU_LATCH_INPUT, 0);
if (ret)
return ret;
if (clk_hw_is_enabled(hw)) {
ret = wait_for_pll_enable_lock(pll);
if (ret)
return ret;
}
return 0;
}
static int clk_lucid_5lpe_pll_postdiv_set_rate(struct clk_hw *hw,
unsigned long rate, unsigned long parent_rate)
{
@ -3331,6 +3392,25 @@ const struct clk_ops clk_alpha_pll_lucid_5lpe_ops = {
};
EXPORT_SYMBOL(clk_alpha_pll_lucid_5lpe_ops);
const struct clk_ops clk_alpha_pll_lucid_5lpe_sdx_cpu_ops = {
.prepare = alpha_pll_lucid_5lpe_prepare,
.unprepare = clk_unprepare_regmap,
.pre_rate_change = clk_pre_change_regmap,
.post_rate_change = clk_post_change_regmap,
.enable = alpha_pll_lucid_5lpe_enable,
.disable = alpha_pll_lucid_5lpe_disable,
.is_enabled = alpha_pll_lucid_is_enabled,
.recalc_rate = alpha_pll_lucid_recalc_rate,
.round_rate = clk_alpha_pll_round_rate,
.set_rate = alpha_pll_lucid_5lpe_sdx_cpu_set_rate,
.debug_init = clk_common_debug_init,
.init = clk_lucid_pll_init,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL(clk_alpha_pll_lucid_5lpe_sdx_cpu_ops);
const struct clk_ops clk_alpha_pll_fixed_lucid_ops = {
.prepare = clk_prepare_regmap,
.unprepare = clk_unprepare_regmap,

View file

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2016, 2018-2020 The Linux Foundation.
* Copyright (c) 2015-2016, 2018-2021 The Linux Foundation.
* All rights reserved.
*/
@ -173,6 +173,7 @@ extern const struct clk_ops clk_alpha_pll_postdiv_zonda_ops;
extern const struct clk_ops clk_alpha_pll_zonda_5lpe_ops;
extern const struct clk_ops clk_alpha_pll_lucid_5lpe_ops;
extern const struct clk_ops clk_alpha_pll_lucid_5lpe_sdx_cpu_ops;
extern const struct clk_ops clk_alpha_pll_fixed_lucid_5lpe_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_lucid_5lpe_ops;
extern const struct clk_ops clk_alpha_pll_slew_ops;

View file

@ -306,7 +306,7 @@ static struct clk_alpha_pll apcs_cpu_pll = {
.fw_name = "bi_tcxo_ao",
},
.num_parents = 1,
.ops = &clk_alpha_pll_lucid_5lpe_ops,
.ops = &clk_alpha_pll_lucid_5lpe_sdx_cpu_ops,
},
.vdd_data = {
.vdd_class = &vdd_pll,
@ -361,7 +361,6 @@ static struct regmap_config cpu_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x3C,
.fast_io = true,
};

View file

@ -240,7 +240,7 @@ static const char *const gcc_debug_mux_parent_names[] = {
};
static int gcc_debug_mux_sels[] = {
0xBA, /* cpu_cc_debug_mux */
0xBF, /* cpu_cc_debug_mux */
0x43, /* disp_cc_debug_mux */
0x67, /* gcc_ahb2phy_csi_clk */
0x68, /* gcc_ahb2phy_usb_clk */
@ -349,7 +349,7 @@ static int gcc_debug_mux_sels[] = {
0x15B, /* gcc_video_venus_ctl_clk */
0x3F, /* gcc_video_xo_clk */
0xFB, /* gpu_cc_debug_mux */
0xA9, /* mc_cc_debug_mux */
0xAE, /* mc_cc_debug_mux */
0x38, /* measure_only_gcc_camera_ahb_clk */
0x40, /* measure_only_gcc_camera_xo_clk */
0xBA, /* measure_only_gcc_cpuss_gnoc_clk */

View file

@ -661,7 +661,10 @@ static struct regmap_config gdsc_regmap_config = {
void gdsc_debug_print_regs(struct regulator *regulator)
{
struct gdsc *sc = rdev_get_drvdata(regulator->rdev);
struct regulator_dev *rdev = regulator->rdev;
struct gdsc *sc = rdev_get_drvdata(rdev);
struct regulator *reg;
const char *supply_name;
uint32_t regvals[3] = {0};
int ret;
@ -670,6 +673,23 @@ void gdsc_debug_print_regs(struct regulator *regulator)
return;
}
ww_mutex_lock(&rdev->mutex, NULL);
if (rdev->open_count)
pr_info("%-32s EN\n", "Device-Supply");
list_for_each_entry(reg, &rdev->consumer_list, list) {
if (reg->supply_name)
supply_name = reg->supply_name;
else
supply_name = "(null)-(null)";
pr_info("%-32s %c\n", supply_name,
(reg->enable_count ? 'Y' : 'N'));
}
ww_mutex_unlock(&rdev->mutex);
ret = regmap_bulk_read(sc->regmap, REG_OFFSET, regvals,
gdsc_regmap_config.max_register ? 3 : 1);
if (ret) {

View file

@ -2632,7 +2632,7 @@ int a6xx_gmu_probe(struct kgsl_device *device,
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
struct resource *res;
int ret;
int ret, i;
gmu->pdev = pdev;
@ -2662,7 +2662,20 @@ int a6xx_gmu_probe(struct kgsl_device *device,
ret = devm_clk_bulk_get_all(&pdev->dev, &gmu->clks);
if (ret < 0)
return ret;
/*
* Voting for apb_pclk will enable power and clocks required for
* QDSS path to function. However, if CORESIGHT is not enabled,
* QDSS is essentially unusable. Hence, if QDSS cannot be used,
* don't vote for this clock.
*/
if (!IS_ENABLED(CONFIG_CORESIGHT)) {
for (i = 0; i < ret; i++) {
if (!strcmp(gmu->clks[i].id, "apb_pclk")) {
gmu->clks[i].clk = NULL;
break;
}
}
}
gmu->num_clks = ret;
/* Set up GMU IOMMU and shared memory with GMU */
@ -2935,6 +2948,8 @@ static int a6xx_boot(struct adreno_device *adreno_dev)
kgsl_pwrscale_wake(device);
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -3003,6 +3018,7 @@ static int a6xx_first_boot(struct adreno_device *adreno_dev)
set_bit(GMU_PRIV_FIRST_BOOT_DONE, &gmu->flags);
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -3264,6 +3280,8 @@ static void a6xx_gmu_touch_wakeup(struct adreno_device *adreno_dev)
kgsl_pwrscale_wake(device);
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
@ -500,6 +500,7 @@ static void a6xx_hwsched_touch_wakeup(struct adreno_device *adreno_dev)
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -541,6 +542,8 @@ static int a6xx_hwsched_boot(struct adreno_device *adreno_dev)
kgsl_pwrscale_wake(device);
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -589,6 +592,7 @@ static int a6xx_hwsched_first_boot(struct adreno_device *adreno_dev)
set_bit(GMU_PRIV_FIRST_BOOT_DONE, &gmu->flags);
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);

View file

@ -896,6 +896,7 @@ static int a6xx_boot(struct adreno_device *adreno_dev)
set_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -934,6 +935,7 @@ static void a6xx_rgmu_touch_wakeup(struct adreno_device *adreno_dev)
set_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -1002,6 +1004,7 @@ static int a6xx_first_boot(struct adreno_device *adreno_dev)
set_bit(RGMU_PRIV_FIRST_BOOT_DONE, &rgmu->flags);
set_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
@ -1248,12 +1251,25 @@ static int a6xx_rgmu_regulators_probe(struct a6xx_rgmu_device *rgmu)
static int a6xx_rgmu_clocks_probe(struct a6xx_rgmu_device *rgmu,
struct device_node *node)
{
int ret;
int ret, i;
ret = devm_clk_bulk_get_all(&rgmu->pdev->dev, &rgmu->clks);
if (ret < 0)
return ret;
/*
* Voting for apb_pclk will enable power and clocks required for
* QDSS path to function. However, if CORESIGHT is not enabled,
* QDSS is essentially unusable. Hence, if QDSS cannot be used,
* don't vote for this clock.
*/
if (!IS_ENABLED(CONFIG_CORESIGHT)) {
for (i = 0; i < ret; i++) {
if (!strcmp(rgmu->clks[i].id, "apb_pclk")) {
rgmu->clks[i].clk = NULL;
break;
}
}
}
rgmu->num_clks = ret;
rgmu->gpu_clk = kgsl_of_clk_by_name(rgmu->clks, ret, "core");

View file

@ -304,6 +304,9 @@ static void _retire_timestamp(struct kgsl_drawobj *drawobj)
context->id, drawobj->timestamp,
!!(drawobj->flags & KGSL_DRAWOBJ_END_OF_FRAME));
if (drawobj->flags & KGSL_DRAWOBJ_END_OF_FRAME)
atomic64_inc(&context->proc_priv->frame_count);
/*
* For A3xx we still get the rptr from the CP_RB_RPTR instead of
* rptr scratch out address. At this point GPU clocks turned off.
@ -2355,6 +2358,9 @@ static void retire_cmdobj(struct adreno_device *adreno_dev,
context->id, drawobj->timestamp,
!!(drawobj->flags & KGSL_DRAWOBJ_END_OF_FRAME));
if (drawobj->flags & KGSL_DRAWOBJ_END_OF_FRAME)
atomic64_inc(&context->proc_priv->frame_count);
/*
* For A3xx we still get the rptr from the CP_RB_RPTR instead of
* rptr scratch out address. At this point GPU clocks turned off.

View file

@ -12,6 +12,7 @@
#include <linux/ion.h>
#include <linux/mman.h>
#include <linux/mm_types.h>
#include <linux/msm_kgsl.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/pm_runtime.h>
@ -335,6 +336,27 @@ static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
}
#endif
static void kgsl_process_sub_stats(struct kgsl_process_private *priv,
unsigned int type, uint64_t size)
{
#ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES
struct task_struct *task;
struct mm_struct *mm;
task = get_pid_task(priv->pid, PIDTYPE_PID);
if (task) {
mm = get_task_mm(task);
if (mm) {
add_mm_counter(mm, MM_UNRECLAIMABLE,
-(size >> PAGE_SHIFT));
mmput(mm);
}
put_task_struct(task);
}
#endif
atomic64_sub(size, &priv->stats[type].cur);
}
void
kgsl_mem_entry_destroy(struct kref *kref)
{
@ -349,7 +371,7 @@ kgsl_mem_entry_destroy(struct kref *kref)
/* pull out the memtype before the flags get cleared */
memtype = kgsl_memdesc_usermem_type(&entry->memdesc);
atomic64_sub(entry->memdesc.size, &entry->priv->stats[memtype].cur);
kgsl_process_sub_stats(entry->priv, memtype, entry->memdesc.size);
/* Detach from process list */
kgsl_mem_entry_detach_process(entry);
@ -1043,6 +1065,24 @@ done:
return private;
}
int kgsl_gpu_frame_count(pid_t pid, u64 *frame_count)
{
struct kgsl_process_private *p;
if (!frame_count)
return -EINVAL;
p = kgsl_process_private_find(pid);
if (!p)
return -ENOENT;
*frame_count = atomic64_read(&p->frame_count);
kgsl_process_private_put(p);
return 0;
}
EXPORT_SYMBOL(kgsl_gpu_frame_count);
static int kgsl_close_device(struct kgsl_device *device)
{
int result = 0;
@ -2753,10 +2793,12 @@ static void kgsl_process_add_stats(struct kgsl_process_private *priv,
if (ret > priv->stats[type].max)
priv->stats[type].max = ret;
#ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES
add_mm_counter(current->mm, MM_UNRECLAIMABLE, (size >> PAGE_SHIFT));
#endif
}
long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{

View file

@ -5,12 +5,12 @@
#ifndef __KGSL_H
#define __KGSL_H
#include <uapi/linux/msm_kgsl.h>
#include <linux/cdev.h>
#include <linux/compat.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/mm.h>
#include <linux/msm_kgsl.h>
#include <linux/uaccess.h>
#include "kgsl_gmu_core.h"

View file

@ -1,12 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013-2017,2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2017,2019,2021 The Linux Foundation. All rights reserved.
*/
#ifndef __KGSL_COMPAT_H
#define __KGSL_COMPAT_H
#include <uapi/linux/msm_kgsl.h>
#include <linux/compat.h>
#include <linux/msm_kgsl.h>
#ifdef CONFIG_COMPAT

View file

@ -437,6 +437,7 @@ struct kgsl_context {
* @fd_count: Counter for the number of FDs for this process
* @ctxt_count: Count for the number of contexts for this process
* @ctxt_count_lock: Spinlock to protect ctxt_count
* @frame_count: Count for the number of frames processed
*/
struct kgsl_process_private {
unsigned long priv;
@ -460,6 +461,7 @@ struct kgsl_process_private {
int fd_count;
atomic_t ctxt_count;
spinlock_t ctxt_count_lock;
atomic64_t frame_count;
};
/**

View file

@ -2511,9 +2511,10 @@ int kgsl_iommu_probe(struct kgsl_device *device)
*/
kgsl_iommu_map_globals(mmu, mmu->defaultpagetable);
kgsl_iommu_map_globals(mmu, mmu->lpac_pagetable);
device->qdss_desc = kgsl_allocate_global_fixed(device,
"qcom,gpu-qdss-stm", "gpu-qdss");
/* QDSS is supported only when CORESIGHT is enabled */
if (IS_ENABLED(CONFIG_CORESIGHT))
device->qdss_desc = kgsl_allocate_global_fixed(device,
"qcom,gpu-qdss-stm", "gpu-qdss");
device->qtimer_desc = kgsl_allocate_global_fixed(device,
"qcom,gpu-timer", "gpu-qtimer");

View file

@ -450,6 +450,11 @@ done:
pcount++;
}
#ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES
mod_node_page_state(page_pgdat(page), NR_UNRECLAIMABLE_PAGES,
(1 << order));
#endif
return pcount;
eagain:
@ -521,6 +526,11 @@ static void kgsl_pool_free_page(struct page *page)
page_order = compound_order(page);
#ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES
mod_node_page_state(page_pgdat(page), NR_UNRECLAIMABLE_PAGES,
-(1 << page_order));
#endif
if (!kgsl_pool_max_pages ||
(kgsl_pool_size_total() < kgsl_pool_max_pages)) {
pool = _kgsl_get_pool_from_order(page_order);

View file

@ -4,6 +4,7 @@
*/
#include <linux/interconnect.h>
#include <linux/msm_kgsl.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@ -1426,6 +1427,9 @@ static int _get_clocks(struct kgsl_device *device)
for (i = 0; i < KGSL_MAX_CLKS; i++) {
if (pwr->grp_clks[i] || strcmp(clocks[i], name))
continue;
/* apb_pclk should only be enabled if CORESIGHT is enabled */
if (!strcmp(name, "apb_pclk") && !IS_ENABLED(CONFIG_CORESIGHT))
continue;
pwr->grp_clks[i] = devm_clk_get(dev, name);
@ -1875,6 +1879,7 @@ static int _wake(struct kgsl_device *device)
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
device->ftbl->deassert_gbif_halt(device);
pwr->last_stat_updated = ktime_get();
/*
* No need to turn on/off irq here as it no longer affects
* power collapse
@ -2255,3 +2260,42 @@ int kgsl_pwrctrl_set_default_gpu_pwrlevel(struct kgsl_device *device)
/* Request adjusted DCVS level */
return device->ftbl->gpu_clock_set(device, pwr->active_pwrlevel);
}
int kgsl_gpu_num_freqs(void)
{
struct kgsl_device *device = kgsl_get_device(0);
if (!device)
return -ENODEV;
return device->pwrctrl.num_pwrlevels;
}
EXPORT_SYMBOL(kgsl_gpu_num_freqs);
int kgsl_gpu_stat(struct kgsl_gpu_freq_stat *stats, u32 numfreq)
{
struct kgsl_device *device = kgsl_get_device(0);
struct kgsl_pwrctrl *pwr;
int i;
if (!device)
return -ENODEV;
pwr = &device->pwrctrl;
if (!stats || (numfreq < pwr->num_pwrlevels))
return -EINVAL;
mutex_lock(&device->mutex);
kgsl_pwrscale_update_stats(device);
for (i = 0; i < pwr->num_pwrlevels; i++) {
stats[i].freq = pwr->pwrlevels[i].gpu_freq;
stats[i].active_time = pwr->clock_times[i];
stats[i].idle_time = pwr->time_in_pwrlevel[i] - pwr->clock_times[i];
}
mutex_unlock(&device->mutex);
return 0;
}
EXPORT_SYMBOL(kgsl_gpu_stat);

View file

@ -175,6 +175,10 @@ struct kgsl_pwrctrl {
u32 minbw_timeout;
/** @ddr_qos_devfreq: Devfreq device for setting DDR qos policy */
struct devfreq *ddr_qos_devfreq;
/** @time_in_pwrlevel: Each pwrlevel active duration in usec */
u64 time_in_pwrlevel[KGSL_MAX_PWRLEVELS];
/** @last_stat_updated: The last time stats were updated */
ktime_t last_stat_updated;
};
int kgsl_pwrctrl_init(struct kgsl_device *device);

View file

@ -122,6 +122,7 @@ void kgsl_pwrscale_update_stats(struct kgsl_device *device)
if (device->state == KGSL_STATE_ACTIVE) {
struct kgsl_power_stats stats;
ktime_t cur_time = ktime_get();
device->ftbl->power_stats(device, &stats);
device->pwrscale.accum_stats.busy_time += stats.busy_time;
@ -129,6 +130,9 @@ void kgsl_pwrscale_update_stats(struct kgsl_device *device)
device->pwrscale.accum_stats.ram_wait += stats.ram_wait;
pwrctrl->clock_times[pwrctrl->active_pwrlevel] +=
stats.busy_time;
pwrctrl->time_in_pwrlevel[pwrctrl->active_pwrlevel] +=
ktime_us_delta(cur_time, pwrctrl->last_stat_updated);
pwrctrl->last_stat_updated = cur_time;
}
}

View file

@ -952,6 +952,11 @@ static void kgsl_contiguous_free(struct kgsl_memdesc *memdesc)
atomic_long_sub(memdesc->size, &kgsl_driver.stats.coherent);
#ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES
mod_node_page_state(page_pgdat(phys_to_page(memdesc->physaddr)),
NR_UNRECLAIMABLE_PAGES, -(memdesc->size >> PAGE_SHIFT));
#endif
_kgsl_contiguous_free(memdesc);
}
@ -961,6 +966,7 @@ static void kgsl_free_secure_system_pages(struct kgsl_memdesc *memdesc)
int i;
struct scatterlist *sg;
int ret = unlock_sgt(memdesc->sgt);
int order = get_order(PAGE_SIZE);
if (ret) {
/*
@ -979,7 +985,11 @@ static void kgsl_free_secure_system_pages(struct kgsl_memdesc *memdesc)
for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) {
struct page *page = sg_page(sg);
__free_pages(page, get_order(PAGE_SIZE));
__free_pages(page, order);
#ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES
mod_node_page_state(page_pgdat(page), NR_UNRECLAIMABLE_PAGES,
-(1 << order));
#endif
}
sg_free_table(memdesc->sgt);
@ -1032,15 +1042,20 @@ static void kgsl_free_pool_pages(struct kgsl_memdesc *memdesc)
static void kgsl_free_system_pages(struct kgsl_memdesc *memdesc)
{
int i;
int i, order = get_order(PAGE_SIZE);
kgsl_paged_unmap_kernel(memdesc);
WARN_ON(memdesc->hostptr);
atomic_long_sub(memdesc->size, &kgsl_driver.stats.page_alloc);
for (i = 0; i < memdesc->page_count; i++)
__free_pages(memdesc->pages[i], get_order(PAGE_SIZE));
for (i = 0; i < memdesc->page_count; i++) {
__free_pages(memdesc->pages[i], order);
#ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES
mod_node_page_state(page_pgdat(memdesc->pages[i]),
NR_UNRECLAIMABLE_PAGES, -(1 << order));
#endif
}
memdesc->page_count = 0;
kvfree(memdesc->pages);
@ -1087,6 +1102,7 @@ static int kgsl_system_alloc_pages(u64 size, struct page ***pages,
struct scatterlist sg;
struct page **local;
int i, npages = size >> PAGE_SHIFT;
int order = get_order(PAGE_SIZE);
local = kvcalloc(npages, sizeof(*pages), GFP_KERNEL);
if (!local)
@ -1098,8 +1114,13 @@ static int kgsl_system_alloc_pages(u64 size, struct page ***pages,
local[i] = alloc_pages(gfp, get_order(PAGE_SIZE));
if (!local[i]) {
for (i = i - 1; i >= 0; i--)
__free_pages(local[i], get_order(PAGE_SIZE));
for (i = i - 1; i >= 0; i--) {
#ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES
mod_node_page_state(page_pgdat(local[i]),
NR_UNRECLAIMABLE_PAGES, -(1 << order));
#endif
__free_pages(local[i], order);
}
kvfree(local);
return -ENOMEM;
}
@ -1110,6 +1131,10 @@ static int kgsl_system_alloc_pages(u64 size, struct page ***pages,
sg_dma_address(&sg) = page_to_phys(local[i]);
dma_sync_sg_for_device(dev, &sg, 1, DMA_BIDIRECTIONAL);
#ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES
mod_node_page_state(page_pgdat(local[i]), NR_UNRECLAIMABLE_PAGES,
(1 << order));
#endif
}
*pages = local;
@ -1256,9 +1281,14 @@ static int kgsl_alloc_contiguous(struct kgsl_device *device,
memdesc->ops = &kgsl_contiguous_ops;
ret = _kgsl_alloc_contiguous(&device->pdev->dev, memdesc, size, 0);
if (!ret)
if (!ret) {
KGSL_STATS_ADD(size, &kgsl_driver.stats.coherent,
&kgsl_driver.stats.coherent_max);
#ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES
mod_node_page_state(page_pgdat(phys_to_page(memdesc->physaddr)),
NR_UNRECLAIMABLE_PAGES, (size >> PAGE_SHIFT));
#endif
}
return ret;
}

View file

@ -90,7 +90,7 @@ EXPORT_SYMBOL_GPL(hid_register_report);
* Register a new field for this report.
*/
static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages)
{
struct hid_field *field;
@ -101,7 +101,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
field = kzalloc((sizeof(struct hid_field) +
usages * sizeof(struct hid_usage) +
values * sizeof(unsigned)), GFP_KERNEL);
usages * sizeof(unsigned)), GFP_KERNEL);
if (!field)
return NULL;
@ -300,7 +300,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
usages = max_t(unsigned, parser->local.usage_index,
parser->global.report_count);
field = hid_register_field(report, usages, parser->global.report_count);
field = hid_register_field(report, usages);
if (!field)
return 0;

View file

@ -16,6 +16,7 @@
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
@ -173,10 +174,20 @@
#define CAL_RC_CLK_AUTO_VAL 1
#define CAL_RC_CLK_MANUAL_VAL 2
/* These registers are only applicable for PM5100 */
#define HAP_CFG_HPWR_INTF_CTL_REG 0x80
#define INTF_CTL_MASK GENMASK(1, 0)
#define INTF_CTL_BOB 1
#define INTF_CTL_BHARGER 2
#define HAP_CFG_VHPWR_REG 0x84
#define VHPWR_STEP_MV 32
/* version register definitions for HAPTICS_PATTERN module */
#define HAP_PTN_REVISION2_REG 0x01
#define HAP_PTN_V1 0x1
#define HAP_PTN_V2 0x2
#define HAP_PTN_V3 0x3
/* status register definition for HAPTICS_PATTERN module */
#define HAP_PTN_FIFO_READY_STS_REG 0x08
@ -267,10 +278,6 @@
#define F_LRA_VARIATION_HZ 5
#define NON_HBOOST_MAX_VMAX_MV 4000
#define MAX_FIFO_SAMPLES(chip) \
((chip)->ptn_revision == HAP_PTN_V1 ? 104 : 640)
#define FIFO_EMPTY_THRESHOLD(chip) \
((chip)->ptn_revision == HAP_PTN_V1 ? 48 : 280)
#define is_between(val, min, max) \
(((min) <= (max)) && ((min) <= (val)) && ((val) <= (max)))
#define HAP_BOOST_CLAMP_5V_REG_OFFSET(chip) \
@ -346,6 +353,11 @@ enum custom_effect_param {
CUSTOM_DATA_LEN,
};
enum pmic_type {
PM8350B,
PM5100,
};
static const char * const src_str[] = {
"FIFO",
"DIRECT_PLAY",
@ -495,7 +507,9 @@ struct haptics_chip {
u32 hbst_addr_base;
u8 cfg_revision;
u8 ptn_revision;
u8 hpwr_intf_ctl;
u16 hbst_revision;
enum pmic_type pmic_type;
bool fifo_empty_irq_en;
bool swr_slave_enabled;
bool clamp_at_5v;
@ -507,6 +521,86 @@ struct haptics_reg_info {
u8 val;
};
static inline int get_max_fifo_samples(struct haptics_chip *chip)
{
int val = 0;
switch (chip->ptn_revision) {
case HAP_PTN_V1:
val = 104;
break;
case HAP_PTN_V2:
val = 640;
break;
case HAP_PTN_V3:
val = 1024;
break;
default:
pr_err("Invalid pattern revision\n");
break;
}
return val;
}
static int get_fifo_empty_threshold(struct haptics_chip *chip)
{
int val = 0;
switch (chip->ptn_revision) {
case HAP_PTN_V1:
val = 48;
break;
case HAP_PTN_V2:
val = 280;
break;
case HAP_PTN_V3:
val = 288;
break;
default:
pr_err("Invalid pattern revision\n");
break;
}
return val;
}
static int get_fifo_threshold_per_bit(struct haptics_chip *chip)
{
int val = -EINVAL;
switch (chip->ptn_revision) {
case HAP_PTN_V1:
val = 4;
break;
case HAP_PTN_V2:
val = 40;
break;
case HAP_PTN_V3:
val = 32;
break;
default:
pr_err("Invalid pattern revision\n");
break;
}
return val;
}
static bool is_haptics_external_powered(struct haptics_chip *chip)
{
/* SW based explicit vote */
if (chip->hpwr_vreg)
return true;
/* Implicit voting by HW */
if (chip->pmic_type == PM5100)
return true;
/* Powered by HBOOST */
return false;
}
static int haptics_read(struct haptics_chip *chip,
u16 base, u8 offset, u8 *val, u32 length)
{
@ -890,7 +984,7 @@ static int haptics_get_closeloop_lra_period_v2(
rc_clk_cal = ((val[0] & CAL_RC_CLK_MASK) >> CAL_RC_CLK_SHIFT);
/* read auto resonance calibration result */
if (in_boot) {
if (in_boot && (chip->pmic_type == PM8350B)) {
if (chip->hap_cfg_nvmem == NULL) {
dev_dbg(chip->dev, "nvmem device for hap_cfg is not defined\n");
return -EINVAL;
@ -1164,6 +1258,9 @@ static int haptics_boost_vreg_enable(struct haptics_chip *chip, bool en)
int rc;
u8 val;
if (is_haptics_external_powered(chip))
return 0;
if (chip->hap_cfg_nvmem == NULL) {
dev_dbg(chip->dev, "nvmem device for hap_cfg is not defined\n");
return 0;
@ -1208,6 +1305,9 @@ static bool is_boost_vreg_enabled_in_open_loop(struct haptics_chip *chip)
int rc;
u8 val;
if (is_haptics_external_powered(chip))
return false;
rc = haptics_read(chip, chip->hbst_addr_base,
HAP_BOOST_HW_CTRL_FOLLOW_REG, &val, 1);
if (!rc && !(val & FOLLOW_HW_EN_BIT)) {
@ -1229,6 +1329,8 @@ static int haptics_wait_hboost_ready(struct haptics_chip *chip)
int i, rc;
u8 val;
if (is_haptics_external_powered(chip))
return 0;
/*
* Wait ~20ms until hBoost is ready, otherwise
* bail out and return -EBUSY
@ -1325,7 +1427,7 @@ static int haptics_open_loop_drive_config(struct haptics_chip *chip, bool en)
u8 val;
if ((is_boost_vreg_enabled_in_open_loop(chip) ||
chip->hpwr_vreg != NULL) && en) {
is_haptics_external_powered(chip)) && en) {
/* Force VREG_RDY */
rc = haptics_masked_write(chip, chip->cfg_addr_base,
HAP_CFG_VSET_CFG_REG, FORCE_VREG_RDY_BIT,
@ -1357,7 +1459,7 @@ static int haptics_open_loop_drive_config(struct haptics_chip *chip, bool en)
dev_dbg(chip->dev, "Toggle CAL_EN in open-loop-VREG playing\n");
}
} else if (chip->hpwr_vreg == NULL) {
} else if (!is_haptics_external_powered(chip)) {
rc = haptics_masked_write(chip, chip->cfg_addr_base,
HAP_CFG_VSET_CFG_REG,
FORCE_VREG_RDY_BIT, 0);
@ -1619,16 +1721,16 @@ static int haptics_get_available_fifo_memory(struct haptics_chip *chip)
if (rc < 0)
return rc;
if (fill > MAX_FIFO_SAMPLES(chip)) {
if (fill > get_max_fifo_samples(chip)) {
dev_err(chip->dev, "Filled FIFO number %d exceed the max %d\n",
fill, MAX_FIFO_SAMPLES(chip));
fill, get_max_fifo_samples(chip));
return -EINVAL;
} else if (fill == MAX_FIFO_SAMPLES(chip)) {
} else if (fill == get_max_fifo_samples(chip)) {
dev_err(chip->dev, "no FIFO space available\n");
return -EBUSY;
}
available = MAX_FIFO_SAMPLES(chip) - fill;
available = get_max_fifo_samples(chip) - fill;
return available;
}
@ -1717,12 +1819,16 @@ static int haptics_set_fifo_empty_threshold(struct haptics_chip *chip,
u8 reg, thresh_per_bit;
int rc;
rc = get_fifo_threshold_per_bit(chip);
if (rc < 0)
return rc;
thresh_per_bit = rc;
reg = (chip->ptn_revision == HAP_PTN_V1) ?
HAP_PTN_V1_FIFO_EMPTY_CFG_REG : HAP_PTN_V2_FIFO_EMPTY_CFG_REG;
thresh_per_bit = (chip->ptn_revision == HAP_PTN_V1) ?
HAP_PTN_V1_FIFO_THRESH_LSB : HAP_PTN_V2_FIFO_THRESH_LSB;
rc = haptics_masked_write(chip, chip->ptn_addr_base,
reg, EMPTY_THRESH_MASK, thresh / thresh_per_bit);
rc = haptics_masked_write(chip, chip->ptn_addr_base, reg,
EMPTY_THRESH_MASK, (thresh / thresh_per_bit));
if (rc < 0)
dev_err(chip->dev, "Set FIFO empty threshold failed, rc=%d\n",
rc);
@ -1782,7 +1888,7 @@ static int haptics_set_fifo(struct haptics_chip *chip, struct fifo_cfg *fifo)
if (chip->ptn_revision == HAP_PTN_V1 &&
fifo->period_per_s > F_8KHZ &&
fifo->num_s > MAX_FIFO_SAMPLES(chip)) {
fifo->num_s > get_max_fifo_samples(chip)) {
dev_err(chip->dev, "PM8350B v1 doesn't support playing long FIFO pattern higher than 8 KHz play rate\n");
return -EINVAL;
}
@ -1808,7 +1914,7 @@ static int haptics_set_fifo(struct haptics_chip *chip, struct fifo_cfg *fifo)
* more than MAX_FIFO_SAMPLES samples, the rest will be
* written if any FIFO memory is available after playing.
*/
num = min_t(u32, fifo->num_s, MAX_FIFO_SAMPLES(chip));
num = min_t(u32, fifo->num_s, get_max_fifo_samples(chip));
available = haptics_get_available_fifo_memory(chip);
if (available < 0)
return available;
@ -1861,7 +1967,7 @@ static int haptics_load_constant_effect(struct haptics_chip *chip, u8 amplitude)
play->effect = NULL;
/* Fix Vmax to (hpwr_vreg_mv - hdrm_mv) in non-HBOOST regulator case */
if (chip->hpwr_vreg) {
if (is_haptics_external_powered(chip)) {
rc = haptics_get_vmax_headroom_mv(chip, &hdrm_mv);
if (rc < 0)
goto unlock;
@ -2199,7 +2305,7 @@ static u8 get_direct_play_max_amplitude(struct haptics_chip *chip)
u32 amplitude = DIRECT_PLAY_MAX_AMPLITUDE, hdrm_mv;
int rc;
if (chip->hpwr_vreg) {
if (is_haptics_external_powered(chip)) {
rc = haptics_get_vmax_headroom_mv(chip, &hdrm_mv);
if (rc < 0)
return 0;
@ -2477,12 +2583,15 @@ static int haptics_hw_init(struct haptics_chip *chip)
if (rc < 0)
return rc;
rc = haptics_read(chip, chip->hbst_addr_base,
HAP_BOOST_CLAMP_5V_REG_OFFSET(chip), val, 1);
if (rc < 0)
return rc;
if (!is_haptics_external_powered(chip)) {
rc = haptics_read(chip, chip->hbst_addr_base,
HAP_BOOST_CLAMP_5V_REG_OFFSET(chip), val, 1);
if (rc < 0)
return rc;
chip->clamp_at_5v = val[0] & CLAMP_5V_BIT;
}
chip->clamp_at_5v = val[0] & CLAMP_5V_BIT;
/* Config VMAX */
rc = haptics_set_vmax_mv(chip, config->vmax_mv);
if (rc < 0)
@ -2506,8 +2615,29 @@ static int haptics_hw_init(struct haptics_chip *chip)
if (rc < 0)
return rc;
/* Force VREG_RDY if non-HBoost is used for powering haptics */
if (chip->hpwr_vreg) {
if ((chip->pmic_type == PM5100) && !chip->hpwr_vreg) {
/* Indicates if HPWR is BOB or Bharger */
rc = haptics_read(chip, chip->cfg_addr_base,
HAP_CFG_HPWR_INTF_CTL_REG, val, 1);
if (rc < 0)
return rc;
chip->hpwr_intf_ctl = val[0] & INTF_CTL_MASK;
/* Read HPWR voltage to adjust the VMAX */
if (chip->hpwr_voltage_mv == 0 &&
chip->hpwr_intf_ctl == INTF_CTL_BOB) {
rc = haptics_read(chip, chip->cfg_addr_base,
HAP_CFG_VHPWR_REG, val, 1);
if (rc < 0)
return rc;
chip->hpwr_voltage_mv = val[0] * VHPWR_STEP_MV;
}
}
if (is_haptics_external_powered(chip)) {
/* Force VREG_RDY if non-HBoost is used for powering haptics */
rc = haptics_masked_write(chip, chip->cfg_addr_base,
HAP_CFG_VSET_CFG_REG, FORCE_VREG_RDY_BIT,
FORCE_VREG_RDY_BIT);
@ -2597,9 +2727,9 @@ static irqreturn_t fifo_empty_irq_handler(int irq, void *data)
* memory, defer the stop into erase() function.
*/
num = haptics_get_available_fifo_memory(chip);
if (num != MAX_FIFO_SAMPLES(chip)) {
if (num != get_max_fifo_samples(chip)) {
dev_dbg(chip->dev, "%d FIFO samples still in playing\n",
MAX_FIFO_SAMPLES(chip) - num);
get_max_fifo_samples(chip) - num);
goto unlock;
}
@ -3686,14 +3816,21 @@ static int haptics_get_revision(struct haptics_chip *chip)
return rc;
chip->ptn_revision = val[0];
rc = haptics_read(chip, chip->hbst_addr_base,
HAP_BOOST_REVISION1, val, 2);
if (rc < 0)
return rc;
chip->hbst_revision = (val[1] << 8) | val[0];
dev_dbg(chip->dev, "haptics revision: HAP_CFG %#x, HAP_PTN %#x, HAP_HBST %#x\n",
chip->cfg_revision, chip->ptn_revision, chip->hbst_revision);
if (is_haptics_external_powered(chip)) {
dev_dbg(chip->dev, "haptics revision: HAP_CFG %#x, HAP_PTN %#x\n",
chip->cfg_revision, chip->ptn_revision);
} else {
rc = haptics_read(chip, chip->hbst_addr_base,
HAP_BOOST_REVISION1, val, 2);
if (rc < 0)
return rc;
chip->hbst_revision = (val[1] << 8) | val[0];
dev_dbg(chip->dev, "haptics revision: HAP_CFG %#x, HAP_PTN %#x, HAP_HBST %#x\n",
chip->cfg_revision, chip->ptn_revision, chip->hbst_revision);
}
return 0;
}
@ -3791,13 +3928,14 @@ static int haptics_parse_dt(struct haptics_chip *chip)
chip->ptn_addr_base = be32_to_cpu(*addr);
addr = of_get_address(node, 2, NULL, NULL);
if (!addr) {
if (!addr && !is_haptics_external_powered(chip)) {
dev_err(chip->dev, "Read HAPTICS_HBOOST address failed\n");
rc = -EINVAL;
goto free_pbs;
} else if (addr != NULL) {
chip->hbst_addr_base = be32_to_cpu(*addr);
}
chip->hbst_addr_base = be32_to_cpu(*addr);
rc = haptics_get_revision(chip);
if (rc < 0) {
dev_err(chip->dev, "Get revision failed, rc=%d\n", rc);
@ -3820,12 +3958,12 @@ static int haptics_parse_dt(struct haptics_chip *chip)
goto free_pbs;
}
config->fifo_empty_thresh = FIFO_EMPTY_THRESHOLD(chip);
config->fifo_empty_thresh = get_fifo_empty_threshold(chip);
of_property_read_u32(node, "qcom,fifo-empty-threshold",
&config->fifo_empty_thresh);
if (config->fifo_empty_thresh >= MAX_FIFO_SAMPLES(chip)) {
if (config->fifo_empty_thresh >= get_max_fifo_samples(chip)) {
dev_err(chip->dev, "FIFO empty threshold (%d) should be less than %d\n",
config->fifo_empty_thresh, MAX_FIFO_SAMPLES(chip));
config->fifo_empty_thresh, get_max_fifo_samples(chip));
rc = -EINVAL;
goto free_pbs;
}
@ -4044,7 +4182,7 @@ static u32 get_lra_impedance_capable_max(struct haptics_chip *chip)
if (chip->clamp_at_5v)
mohms = MAX_IMPEDANCE_MOHM / 2;
if (chip->hpwr_vreg)
if (is_haptics_external_powered(chip))
mohms = (chip->hpwr_voltage_mv * 1000) / MIN_ISC_MA;
dev_dbg(chip->dev, "LRA impedance capable max: %u mohms\n", mohms);
@ -4210,7 +4348,7 @@ static int haptics_detect_lra_frequency(struct haptics_chip *chip)
goto restore;
/* Fix Vmax to (hpwr_vreg_mv - hdrm_mv) in non-HBOOST regulator case */
if (chip->hpwr_vreg)
if (is_haptics_external_powered(chip))
vmax_mv = chip->hpwr_voltage_mv - LRA_CALIBRATION_VMAX_HDRM_MV;
rc = haptics_set_vmax_mv(chip, vmax_mv);
@ -4401,6 +4539,9 @@ static int haptics_probe(struct platform_device *pdev)
return -ENXIO;
}
chip->pmic_type =
(enum pmic_type)(uintptr_t)of_device_get_match_data(chip->dev);
rc = haptics_parse_dt(chip);
if (rc < 0) {
dev_err(chip->dev, "Parse device-tree failed, rc = %d\n", rc);
@ -4572,8 +4713,18 @@ static const struct dev_pm_ops haptics_pm_ops = {
};
static const struct of_device_id haptics_match_table[] = {
{ .compatible = "qcom,hv-haptics" },
{ .compatible = "qcom,pm8350b-haptics" },
{
.compatible = "qcom,hv-haptics",
.data = (void *)PM8350B,
},
{
.compatible = "qcom,pm8350b-haptics",
.data = (void *)PM8350B,
},
{
.compatible = "qcom,pm5100-haptics",
.data = (void *)PM5100,
},
{},
};

View file

@ -20,6 +20,7 @@
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/reset.h>
#include <linux/pinctrl/consumer.h>
#include "sdhci-pltfm.h"
#include "cqhci.h"
@ -4379,6 +4380,13 @@ static int sdhci_msm_probe(struct platform_device *pdev)
}
}
/* Toggle wlan_en pin to reset SDIO card to correct state */
if (host->mmc->pm_caps & MMC_PM_KEEP_POWER) {
pinctrl_pm_select_sleep_state(&pdev->dev);
mdelay(1);
pinctrl_pm_select_default_state(&pdev->dev);
}
/* Reset the vendor spec register to power on reset state */
writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
host->ioaddr + msm_offset->core_vendor_spec);

View file

@ -2941,7 +2941,14 @@ static int msm_nand_read_partial_page(struct mtd_info *mtd,
no_copy = false;
ops->datbuf = no_copy ? actual_buf : bounce_buf;
if (info->nand_chip.caps & MSM_NAND_CAP_PAGE_SCOPE_READ)
/*
* Do a Pagescope read only if PAGE_SCOPE_READ is enabled
* and request length is greater than codeword size or
* the page offset is not aligned to start of the page.
*/
if ((info->nand_chip.caps & MSM_NAND_CAP_PAGE_SCOPE_READ) &&
((len > ONE_CODEWORD_SIZE) || (offset != 0)))
err = msm_nand_read_pagescope(mtd, aligned_from, ops);
else {
if ((len <= ONE_CODEWORD_SIZE) && (offset == 0))

View file

@ -79,9 +79,9 @@
#define WLAN_BOOTSTRAP_GPIO_NAME "wlan-bootstrap-gpio"
#define PM_OPTIONS 0
#define PM_OPTIONS_SUSPEND_LINK_DOWN \
(MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN)
(PM_OPTIONS | MSM_PCIE_CONFIG_LINKDOWN)
#define PM_OPTIONS_RESUME_LINK_DOWN \
(MSM_PCIE_CONFIG_NO_CFG_RESTORE)
(PM_OPTIONS)
#define SOC_SWREG_VOLT_MAX 1200000
#define SOC_SWREG_VOLT_MIN 1200000
@ -231,6 +231,7 @@ static struct cnss_data {
bool pci_register_again;
bool notify_modem_status;
struct pci_saved_state *saved_state;
struct pci_saved_state *default_state;
u16 revision_id;
bool recovery_in_progress;
atomic_t fw_available;
@ -1518,7 +1519,7 @@ int cnss_pci_load_and_free_saved_state(struct pci_dev *dev,
int cnss_msm_pcie_shadow_control(struct pci_dev *dev, bool enable)
{
return msm_pcie_shadow_control(dev, enable);
return 0;
}
int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
@ -1528,7 +1529,12 @@ int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
int cnss_msm_pcie_recover_config(struct pci_dev *dev)
{
return msm_pcie_recover_config(dev);
if (penv->saved_state)
cnss_pci_load_and_free_saved_state(dev, &penv->saved_state);
else
pci_load_saved_state(dev, penv->default_state);
pci_restore_state(dev);
}
int cnss_msm_pcie_register_event(struct msm_pcie_register_event *reg)
@ -1661,6 +1667,8 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev,
if (penv->pcie_link_state) {
pci_save_state(pdev);
penv->saved_state = cnss_pci_store_saved_state(pdev);
/* Save default config space */
penv->default_state = cnss_pci_store_saved_state(pdev);
ret = cnss_msm_pcie_pm_control(MSM_PCIE_SUSPEND,
cnss_get_pci_dev_bus_number(pdev),
@ -1734,6 +1742,9 @@ static void cnss_wlan_pci_remove(struct pci_dev *pdev)
if (!penv)
return;
if (penv->default_state)
pci_load_and_free_saved_state(penv->pdev, &penv->default_state);
dev = &penv->pldev->dev;
cnss_pcie_reset_platform_ops(dev);
device_remove_file(dev, &dev_attr_wlan_setup);

View file

@ -3053,6 +3053,10 @@ static void cnss_init_control_params(struct cnss_plat_data *plat_priv)
plat_priv->ctrl_params.qmi_timeout = CNSS_QMI_TIMEOUT_DEFAULT;
plat_priv->ctrl_params.bdf_type = CNSS_BDF_TYPE_DEFAULT;
plat_priv->ctrl_params.time_sync_period = CNSS_TIME_SYNC_PERIOD_DEFAULT;
/* Set adsp_pc_enabled default value to true as ADSP pc is always
* enabled by default
*/
plat_priv->adsp_pc_enabled = true;
}
static void cnss_get_pm_domain_info(struct cnss_plat_data *plat_priv)

View file

@ -505,6 +505,7 @@ struct cnss_plat_data {
u32 is_converged_dt;
struct device_node *dev_node;
u64 feature_list;
bool adsp_pc_enabled;
};
#ifdef CONFIG_ARCH_QCOM

View file

@ -1802,6 +1802,13 @@ static int cnss_wlan_adsp_pc_enable(struct cnss_pci_data *pci_priv,
struct pci_dev *pci_dev = pci_priv->pci_dev;
int ret = 0;
u32 pm_options = PM_OPTIONS_DEFAULT;
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
if (plat_priv->adsp_pc_enabled == control) {
cnss_pr_dbg("ADSP power collapse already %s\n",
control ? "Enabled" : "Disabled");
return 0;
}
if (control)
pm_options &= ~MSM_PCIE_CONFIG_NO_DRV_PC;
@ -1814,6 +1821,7 @@ static int cnss_wlan_adsp_pc_enable(struct cnss_pci_data *pci_priv,
return ret;
cnss_pr_dbg("%s ADSP power collapse\n", control ? "Enable" : "Disable");
plat_priv->adsp_pc_enabled = control;
return 0;
}
#else
@ -2978,6 +2986,7 @@ int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv)
static bool cnss_pci_is_drv_supported(struct cnss_pci_data *pci_priv)
{
struct pci_dev *root_port = pci_find_pcie_root_port(pci_priv->pci_dev);
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
struct device_node *root_of_node;
bool drv_supported = false;
@ -2997,6 +3006,9 @@ static bool cnss_pci_is_drv_supported(struct cnss_pci_data *pci_priv)
drv_supported ? "supported" : "not supported");
pci_priv->drv_supported = drv_supported;
if (drv_supported)
plat_priv->cap.cap_flag |= CNSS_HAS_DRV_SUPPORT;
return drv_supported;
}

View file

@ -4041,7 +4041,7 @@ static void hwsim_virtio_rx_work(struct work_struct *work)
}
vq = hwsim_vqs[HWSIM_VQ_RX];
sg_init_one(sg, skb->head, skb_end_offset(skb));
err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL);
err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_ATOMIC);
if (WARN(err, "virtqueue_add_inbuf returned %d\n", err))
nlmsg_free(skb);
else

View file

@ -53,6 +53,9 @@ enum qpnp_regulator_logical_type {
QPNP_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS,
QPNP_REGULATOR_LOGICAL_TYPE_ULT_LDO,
QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS2,
QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS3,
QPNP_REGULATOR_LOGICAL_TYPE_LDO_510,
QPNP_REGULATOR_LOGICAL_TYPE_HFSMPS,
};
enum qpnp_regulator_type {
@ -103,6 +106,17 @@ enum qpnp_regulator_subtype {
QPNP_REGULATOR_SUBTYPE_ULT_HF_CTL2 = 0x0E,
QPNP_REGULATOR_SUBTYPE_ULT_HF_CTL3 = 0x0F,
QPNP_REGULATOR_SUBTYPE_ULT_HF_CTL4 = 0x10,
QPNP_REGULATOR_SUBTYPE_HFSMPS_510 = 0x0A,
QPNP_REGULATOR_SUBTYPE_FTSMPS_510 = 0x0B,
QPNP_REGULATOR_SUBTYPE_LV_P150_510 = 0x71,
QPNP_REGULATOR_SUBTYPE_LV_P300_510 = 0x72,
QPNP_REGULATOR_SUBTYPE_LV_P600_510 = 0x73,
QPNP_REGULATOR_SUBTYPE_N300_510 = 0x6A,
QPNP_REGULATOR_SUBTYPE_N600_510 = 0x6B,
QPNP_REGULATOR_SUBTYPE_N1200_510 = 0x6C,
QPNP_REGULATOR_SUBTYPE_MV_P50_510 = 0x7A,
QPNP_REGULATOR_SUBTYPE_MV_P150_510 = 0x7B,
QPNP_REGULATOR_SUBTYPE_MV_P600_510 = 0x7D,
};
/* First common register layout used by older devices */
@ -130,6 +144,11 @@ enum qpnp_common2_regulator_registers {
QPNP_COMMON2_REG_STEP_CTRL = 0x61,
};
enum qpnp_common3_regulator_registers {
QPNP_COMMON3_REG_STEP_CTRL = 0x3C,
};
enum qpnp_ldo_registers {
QPNP_LDO_REG_SOFT_START = 0x4C,
};
@ -191,6 +210,15 @@ enum qpnp_common2_control_register_index {
#define QPNP_COMMON2_MODE_MASK 0x07
/* Third common regulator mode register values */
#define QPNP_COMMON3_MODE_BYPASS 2
#define QPNP_COMMON3_MODE_RETENTION 3
#define QPNP_COMMON3_MODE_LPM 4
#define QPNP_COMMON3_MODE_AUTO 6
#define QPNP_COMMON3_MODE_HPM 7
#define QPNP_COMMON3_MODE_MASK 0x07
/* Common regulator pull down control register layout */
#define QPNP_COMMON_PULL_DOWN_ENABLE_MASK 0x80
@ -251,6 +279,9 @@ enum qpnp_common2_control_register_index {
#define QPNP_FTSMPS2_STEP_MARGIN_NUM 10
#define QPNP_FTSMPS2_STEP_MARGIN_DEN 11
/* slew_rate has units of uV/us. */
#define QPNP_COMMON3_FTSMPS3_SLEW_RATE_38p4 38400
/*
* This voltage in uV is returned by get_voltage functions when there is no way
* to determine the current voltage level. It is needed because the regulator
@ -451,6 +482,26 @@ static struct qpnp_voltage_range ftsmps426_ranges[] = {
VOLTAGE_RANGE(0, 0, 320000, 1352000, 1352000, 4000),
};
static struct qpnp_voltage_range pldo_510_ranges[] = {
VOLTAGE_RANGE(0, 1504000, 1504000, 2000000, 2000000, 8000),
};
static struct qpnp_voltage_range mv_pldo_510_ranges[] = {
VOLTAGE_RANGE(0, 1504000, 1504000, 3544000, 3544000, 8000),
};
static struct qpnp_voltage_range nldo_510_ranges[] = {
VOLTAGE_RANGE(0, 320000, 320000, 1304000, 1304000, 8000),
};
static struct qpnp_voltage_range hfsmps510_ranges[] = {
VOLTAGE_RANGE(0, 320000, 320000, 2040000, 2040000, 8000),
};
static struct qpnp_voltage_range ftsmps510_ranges[] = {
VOLTAGE_RANGE(0, 300000, 300000, 1372000, 1372000, 4000),
};
static struct qpnp_voltage_set_points pldo_set_points = SET_POINTS(pldo_ranges);
static struct qpnp_voltage_set_points nldo1_set_points
= SET_POINTS(nldo1_ranges);
@ -479,6 +530,16 @@ static struct qpnp_voltage_set_points ult_pldo_set_points
= SET_POINTS(ult_pldo_ranges);
static struct qpnp_voltage_set_points ftsmps426_set_points
= SET_POINTS(ftsmps426_ranges);
static struct qpnp_voltage_set_points pldo_510_set_points
= SET_POINTS(pldo_510_ranges);
static struct qpnp_voltage_set_points mv_pldo_510_set_points
= SET_POINTS(mv_pldo_510_ranges);
static struct qpnp_voltage_set_points nldo_510_set_points
= SET_POINTS(nldo_510_ranges);
static struct qpnp_voltage_set_points hfsmps510_set_points
= SET_POINTS(hfsmps510_ranges);
static struct qpnp_voltage_set_points ftsmps510_set_points
= SET_POINTS(ftsmps510_ranges);
static struct qpnp_voltage_set_points none_set_points;
static struct qpnp_voltage_set_points *all_set_points[] = {
@ -497,6 +558,11 @@ static struct qpnp_voltage_set_points *all_set_points[] = {
&ult_nldo_set_points,
&ult_pldo_set_points,
&ftsmps426_set_points,
&pldo_510_set_points,
&mv_pldo_510_set_points,
&nldo_510_set_points,
&hfsmps510_set_points,
&ftsmps510_set_points,
};
/* Determines which label to add to a debug print statement. */
@ -1212,12 +1278,27 @@ static int qpnp_regulator_common2_set_mode(struct regulator_dev *rdev,
* ensures that AUTO mode is re-asserted after switching away from
* forced HPM if it was configured initially.
*/
if (mode == REGULATOR_MODE_NORMAL)
val = QPNP_COMMON2_MODE_HPM;
else if (vreg->init_mode == QPNP_COMMON2_MODE_HPM)
val = QPNP_COMMON2_MODE_LPM;
else
val = vreg->init_mode;
if ((vreg->logical_type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS3) ||
(vreg->logical_type == QPNP_REGULATOR_LOGICAL_TYPE_HFSMPS) ||
(vreg->logical_type == QPNP_REGULATOR_LOGICAL_TYPE_LDO_510)) {
if (mode == REGULATOR_MODE_NORMAL)
val = QPNP_COMMON3_MODE_HPM;
else if (vreg->init_mode == QPNP_COMMON3_MODE_HPM &&
vreg->logical_type !=
QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS3)
val = QPNP_COMMON3_MODE_LPM;
else if (vreg->init_mode == QPNP_COMMON3_MODE_HPM)
val = QPNP_COMMON3_MODE_RETENTION;
else
val = vreg->init_mode;
} else {
if (mode == REGULATOR_MODE_NORMAL)
val = QPNP_COMMON2_MODE_HPM;
else if (vreg->init_mode == QPNP_COMMON2_MODE_HPM)
val = QPNP_COMMON2_MODE_LPM;
else
val = vreg->init_mode;
}
rc = qpnp_vreg_write_optimized(vreg, QPNP_COMMON2_REG_MODE, &val,
&vreg->ctrl_reg[QPNP_COMMON2_IDX_MODE], 1);
@ -1335,6 +1416,18 @@ static const char * const qpnp_common2_mode_label[] = {
[QPNP_COMMON2_MODE_HPM] = "HPM",
};
static const char * const qpnp_common3_mode_label[] = {
[0] = "RSV",
[1] = "RSV",
[2] = "RSV",
[QPNP_COMMON3_MODE_BYPASS] = "BYP",
[QPNP_COMMON3_MODE_RETENTION] = "RET",
[QPNP_COMMON3_MODE_LPM] = "LPM",
[QPNP_COMMON3_MODE_AUTO] = "AUTO",
[QPNP_COMMON3_MODE_HPM] = "HPM",
};
static void qpnp_vreg_show_state(struct regulator_dev *rdev,
enum qpnp_regulator_action action)
{
@ -1495,6 +1588,16 @@ static void qpnp_vreg_show_state(struct regulator_dev *rdev,
action_label, vreg->rdesc.name, enable_label, uV,
mode_label);
break;
case QPNP_REGULATOR_LOGICAL_TYPE_HFSMPS:
case QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS3:
case QPNP_REGULATOR_LOGICAL_TYPE_LDO_510:
mode_reg = vreg->ctrl_reg[QPNP_COMMON_IDX_MODE];
mode_label = qpnp_common3_mode_label[mode_reg
& QPNP_COMMON3_MODE_MASK];
pr_info("%s %-11s: %s, v=%7d uV, mode=%s\n",
action_label, vreg->rdesc.name, enable_label, uV,
mode_label);
break;
default:
break;
}
@ -1618,6 +1721,45 @@ static struct regulator_ops qpnp_ftsmps426_ops = {
.enable_time = qpnp_regulator_common_enable_time,
};
static struct regulator_ops qpnp_hfsmps510_ops = {
.enable = qpnp_regulator_common_enable,
.disable = qpnp_regulator_common_disable,
.is_enabled = qpnp_regulator_common_is_enabled,
.set_voltage = qpnp_regulator_common2_set_voltage,
.get_voltage = qpnp_regulator_common2_get_voltage,
.list_voltage = qpnp_regulator_common_list_voltage,
.set_mode = qpnp_regulator_common2_set_mode,
.get_mode = qpnp_regulator_common2_get_mode,
.get_optimum_mode = qpnp_regulator_common_get_optimum_mode,
.enable_time = qpnp_regulator_common_enable_time,
};
static struct regulator_ops qpnp_ftsmps510_ops = {
.enable = qpnp_regulator_common_enable,
.disable = qpnp_regulator_common_disable,
.is_enabled = qpnp_regulator_common_is_enabled,
.set_voltage = qpnp_regulator_common2_set_voltage,
.get_voltage = qpnp_regulator_common2_get_voltage,
.list_voltage = qpnp_regulator_common_list_voltage,
.set_mode = qpnp_regulator_common2_set_mode,
.get_mode = qpnp_regulator_common2_get_mode,
.get_optimum_mode = qpnp_regulator_common_get_optimum_mode,
.enable_time = qpnp_regulator_common_enable_time,
};
static struct regulator_ops qpnp_ldo_510_ops = {
.enable = qpnp_regulator_common_enable,
.disable = qpnp_regulator_common_disable,
.is_enabled = qpnp_regulator_common_is_enabled,
.set_voltage = qpnp_regulator_common2_set_voltage,
.get_voltage = qpnp_regulator_common2_get_voltage,
.list_voltage = qpnp_regulator_common_list_voltage,
.set_mode = qpnp_regulator_common2_set_mode,
.get_mode = qpnp_regulator_common2_get_mode,
.get_optimum_mode = qpnp_regulator_common_get_optimum_mode,
.enable_time = qpnp_regulator_common_enable_time,
};
/* Maximum possible digital major revision value */
#define INF 0xFF
@ -1679,8 +1821,27 @@ static const struct qpnp_regulator_mapping supported_regulators[] = {
10000),
QPNP_VREG_MAP(ULT_LDO, P50, 0, INF, ULT_LDO, ult_ldo, ult_pldo,
5000),
QPNP_VREG_MAP(FTS, FTS426, 0, INF, FTSMPS2, ftsmps426, ftsmps426,
QPNP_VREG_MAP(FTS, FTS426, 0, INF, FTSMPS2, ftsmps426, ftsmps426,
100000),
QPNP_VREG_MAP(LDO, LV_P150_510, 0, INF, LDO_510, ldo_510, pldo_510,
10000),
QPNP_VREG_MAP(LDO, LV_P300_510, 0, INF, LDO_510, ldo_510, pldo_510,
10000),
QPNP_VREG_MAP(LDO, LV_P600_510, 0, INF, LDO_510, ldo_510, pldo_510,
10000),
QPNP_VREG_MAP(LDO, MV_P50_510, 0, INF, LDO_510, ldo_510, mv_pldo_510,
10000),
QPNP_VREG_MAP(LDO, MV_P150_510, 0, INF, LDO_510, ldo_510, mv_pldo_510,
10000),
QPNP_VREG_MAP(LDO, MV_P600_510, 0, INF, LDO_510, ldo_510, mv_pldo_510,
10000),
QPNP_VREG_MAP(LDO, N300_510, 0, INF, LDO_510, ldo_510, nldo_510, 10000),
QPNP_VREG_MAP(LDO, N600_510, 0, INF, LDO_510, ldo_510, nldo_510, 10000),
QPNP_VREG_MAP(LDO, N1200_510, 0, INF, LDO_510, ldo_510, nldo_510, 10000),
QPNP_VREG_MAP(BUCK, HFSMPS_510, 0, INF, HFSMPS, hfsmps510, hfsmps510,
100000),
QPNP_VREG_MAP(FTS, FTSMPS_510, 0, INF, FTSMPS3, ftsmps510, ftsmps510,
100000),
};
static int qpnp_regulator_match(struct qpnp_regulator *vreg)
@ -1792,10 +1953,18 @@ static int qpnp_regulator_ftsmps2_init_slew_rate(struct qpnp_regulator *vreg)
int i, rc, delay;
u8 reg = 0;
rc = qpnp_vreg_read(vreg, QPNP_COMMON2_REG_STEP_CTRL, &reg, 1);
if (rc) {
vreg_err(vreg, "spmi read failed, rc=%d\n", rc);
return rc;
if (vreg->logical_type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS3) {
rc = qpnp_vreg_read(vreg, QPNP_COMMON3_REG_STEP_CTRL, &reg, 1);
if (rc) {
vreg_err(vreg, "spmi read failed, rc=%d\n", rc);
return rc;
}
} else {
rc = qpnp_vreg_read(vreg, QPNP_COMMON2_REG_STEP_CTRL, &reg, 1);
if (rc) {
vreg_err(vreg, "spmi read failed, rc=%d\n", rc);
return rc;
}
}
/*
@ -1817,14 +1986,18 @@ static int qpnp_regulator_ftsmps2_init_slew_rate(struct qpnp_regulator *vreg)
delay = (reg & QPNP_FTSMPS2_STEP_CTRL_DELAY_MASK)
>> QPNP_FTSMPS2_STEP_CTRL_DELAY_SHIFT;
/* slew_rate has units of uV/us. */
vreg->slew_rate = QPNP_FTSMPS2_CLOCK_RATE * range->step_uV;
vreg->slew_rate /= 1000 * (QPNP_FTSMPS2_STEP_DELAY << delay);
vreg->slew_rate = vreg->slew_rate * QPNP_FTSMPS2_STEP_MARGIN_NUM
/ QPNP_FTSMPS2_STEP_MARGIN_DEN;
if (vreg->logical_type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS3) {
vreg->slew_rate = QPNP_COMMON3_FTSMPS3_SLEW_RATE_38p4 >> delay;
} else {
/* slew_rate has units of uV/us. */
vreg->slew_rate = QPNP_FTSMPS2_CLOCK_RATE * range->step_uV;
vreg->slew_rate /= 1000 * (QPNP_FTSMPS2_STEP_DELAY << delay);
vreg->slew_rate = vreg->slew_rate * QPNP_FTSMPS2_STEP_MARGIN_NUM
/ QPNP_FTSMPS2_STEP_MARGIN_DEN;
/* Ensure that the slew rate is greater than 0. */
vreg->slew_rate = max(vreg->slew_rate, 1);
/* Ensure that the slew rate is greater than 0. */
vreg->slew_rate = max(vreg->slew_rate, 1);
}
return rc;
}
@ -1905,6 +2078,35 @@ static int qpnp_regulator_init_registers(struct qpnp_regulator *vreg,
= QPNP_COMMON2_MODE_LPM;
}
if (type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS3 ||
type == QPNP_REGULATOR_LOGICAL_TYPE_HFSMPS ||
type == QPNP_REGULATOR_LOGICAL_TYPE_LDO_510) {
if (pdata->hpm_enable == QPNP_REGULATOR_ENABLE)
ctrl_reg[QPNP_COMMON2_IDX_MODE]
= QPNP_COMMON3_MODE_HPM;
else if (pdata->auto_mode_enable == QPNP_REGULATOR_ENABLE
&& type == QPNP_REGULATOR_LOGICAL_TYPE_HFSMPS)
ctrl_reg[QPNP_COMMON2_IDX_MODE]
= QPNP_COMMON3_MODE_AUTO;
else if (pdata->hpm_enable == QPNP_REGULATOR_DISABLE
&& ctrl_reg[QPNP_COMMON2_IDX_MODE]
== QPNP_COMMON3_MODE_HPM &&
type != QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS3)
ctrl_reg[QPNP_COMMON2_IDX_MODE]
= QPNP_COMMON3_MODE_LPM;
else if (pdata->hpm_enable == QPNP_REGULATOR_DISABLE
&& ctrl_reg[QPNP_COMMON2_IDX_MODE]
== QPNP_COMMON3_MODE_HPM)
ctrl_reg[QPNP_COMMON2_IDX_MODE]
= QPNP_COMMON3_MODE_RETENTION;
else if (pdata->auto_mode_enable == QPNP_REGULATOR_DISABLE
&& ctrl_reg[QPNP_COMMON2_IDX_MODE]
== QPNP_COMMON2_MODE_AUTO &&
type == QPNP_REGULATOR_LOGICAL_TYPE_HFSMPS)
ctrl_reg[QPNP_COMMON2_IDX_MODE]
= QPNP_COMMON2_MODE_LPM;
}
/* Set up mode pin control. */
if ((type == QPNP_REGULATOR_LOGICAL_TYPE_SMPS
|| type == QPNP_REGULATOR_LOGICAL_TYPE_LDO)
@ -2068,8 +2270,9 @@ static int qpnp_regulator_init_registers(struct qpnp_regulator *vreg,
}
}
/* Calculate the slew rate for FTSMPS2 regulators. */
if (type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS2) {
/* Calculate the slew rate for FTSMPS2 and FTSMPS3 regulators. */
if (type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS2 ||
type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS3) {
rc = qpnp_regulator_ftsmps2_init_slew_rate(vreg);
if (rc) {
vreg_err(vreg, "failed to initialize step rate, rc=%d\n",

View file

@ -445,7 +445,7 @@ static void rproc_rvdev_release(struct device *dev)
/**
* rproc_handle_vdev() - handle a vdev fw resource
* @rproc: the remote processor
* @rsc: the vring resource descriptor
* ptr: the vring resource descriptor
* @avail: size of available data (for sanity checking the image)
*
* This resource entry requests the host to statically register a virtio
@ -469,9 +469,10 @@ static void rproc_rvdev_release(struct device *dev)
*
* Returns 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
static int rproc_handle_vdev(struct rproc *rproc, void *ptr,
int offset, int avail)
{
struct fw_rsc_vdev *rsc = ptr;
struct device *dev = &rproc->dev;
struct rproc_vdev *rvdev;
int i, ret;
@ -587,7 +588,7 @@ void rproc_vdev_release(struct kref *ref)
/**
* rproc_handle_trace() - handle a shared trace buffer resource
* @rproc: the remote processor
* @rsc: the trace resource descriptor
* @ptr: the trace resource descriptor
* @avail: size of available data (for sanity checking the image)
*
* In case the remote processor dumps trace logs into memory,
@ -600,9 +601,10 @@ void rproc_vdev_release(struct kref *ref)
*
* Returns 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
static int rproc_handle_trace(struct rproc *rproc, void *ptr,
int offset, int avail)
{
struct fw_rsc_trace *rsc = ptr;
struct rproc_debug_trace *trace;
struct device *dev = &rproc->dev;
char name[15];
@ -652,7 +654,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
/**
* rproc_handle_devmem() - handle devmem resource entry
* @rproc: remote processor handle
* @rsc: the devmem resource entry
* @ptr: the devmem resource entry
* @avail: size of available data (for sanity checking the image)
*
* Remote processors commonly need to access certain on-chip peripherals.
@ -674,9 +676,10 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
* and not allow firmwares to request access to physical addresses that
* are outside those ranges.
*/
static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
static int rproc_handle_devmem(struct rproc *rproc, void *ptr,
int offset, int avail)
{
struct fw_rsc_devmem *rsc = ptr;
struct rproc_mem_entry *mapping;
struct device *dev = &rproc->dev;
int ret;
@ -853,7 +856,7 @@ static int rproc_release_carveout(struct rproc *rproc,
/**
* rproc_handle_carveout() - handle phys contig memory allocation requests
* @rproc: rproc handle
* @rsc: the resource entry
* @ptr: the resource entry
* @avail: size of available data (for image validation)
*
* This function will handle firmware requests for allocation of physically
@ -869,9 +872,9 @@ static int rproc_release_carveout(struct rproc *rproc,
* pressure is important; it may have a substantial impact on performance.
*/
static int rproc_handle_carveout(struct rproc *rproc,
struct fw_rsc_carveout *rsc,
int offset, int avail)
void *ptr, int offset, int avail)
{
struct fw_rsc_carveout *rsc = ptr;
struct rproc_mem_entry *carveout;
struct device *dev = &rproc->dev;
@ -1028,10 +1031,10 @@ EXPORT_SYMBOL(rproc_of_resm_mem_entry_init);
* enum fw_resource_type.
*/
static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = {
[RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
[RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
[RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
[RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
[RSC_CARVEOUT] = rproc_handle_carveout,
[RSC_DEVMEM] = rproc_handle_devmem,
[RSC_TRACE] = rproc_handle_trace,
[RSC_VDEV] = rproc_handle_vdev,
};
/* handle firmware resource entries before booting the remote processor */

View file

@ -582,7 +582,7 @@ static void ufs_mtk_vreg_set_lpm(struct ufs_hba *hba, bool lpm)
if (!hba->vreg_info.vccq2 || !hba->vreg_info.vcc)
return;
if (lpm & !hba->vreg_info.vcc->enabled)
if (lpm && !hba->vreg_info.vcc->enabled)
regulator_set_mode(hba->vreg_info.vccq2->reg,
REGULATOR_MODE_IDLE);
else if (!lpm)

View file

@ -9077,7 +9077,8 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
(ufs_get_pm_lvl_to_dev_pwr_mode(hba->spm_lvl) ==
hba->curr_dev_pwr_mode) &&
(ufs_get_pm_lvl_to_link_pwr_state(hba->spm_lvl) ==
hba->uic_link_state))
hba->uic_link_state) &&
!hba->dev_info.b_rpm_dev_flush_capable)
goto out;
if (pm_runtime_suspended(hba->dev)) {
@ -9274,6 +9275,7 @@ void ufshcd_remove(struct ufs_hba *hba)
ufs_bsg_remove(hba);
ufs_sysfs_remove_nodes(hba->dev);
scsi_remove_host(hba->host);
destroy_workqueue(hba->eh_wq);
/* disable interrupts */
ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba, true);
@ -9546,6 +9548,7 @@ out_remove_scsi_host:
exit_gating:
ufshcd_exit_clk_scaling(hba);
ufshcd_exit_clk_gating(hba);
destroy_workqueue(hba->eh_wq);
out_disable:
hba->is_irq_enabled = false;
ufshcd_hba_exit(hba);

View file

@ -1462,6 +1462,10 @@ static inline void ufshcd_vops_device_reset(struct ufs_hba *hba)
if (hba->vops && hba->vops->device_reset) {
hba->vops->device_reset(hba);
ufshcd_set_ufs_dev_active(hba);
if (ufshcd_is_wb_allowed(hba)) {
hba->wb_enabled = false;
hba->wb_buf_flush_enabled = false;
}
ufshcd_update_reg_hist(&hba->ufs_stats.dev_reset, 0);
}
}

View file

@ -1050,6 +1050,16 @@ config CDSPRM_VTCM_DYNAMIC_DEBUG
enabled, the vtcm partition details are sent to the CDSP via rpmsg
channel.
config QCOM_SYSMON_SUBSYSTEM_STATS
tristate "Qualcomm Technologies SysMon DSP subsystem stats"
depends on QCOM_SMEM
help
sysMon subsystem stats driver exposes API to query DSP
subsystem's load and power statistics stored in SMEM.
SMEM region for each DSP subsystem is updated periodically
by the respective subsystem. Power stats gets updated after
DSP clock change event.
config QCOM_WDT_CORE
tristate "Qualcomm Technologies, Inc. Watchdog Support"
depends on ARCH_QCOM
@ -1062,6 +1072,15 @@ config QCOM_WDT_CORE
watchdog module must be loaded along with this for watchdog
functionality.
config QCOM_CX_IPEAK
tristate "Common driver to handle Cx iPeak limitation"
help
Cx ipeak HW module is used to limit the current drawn by various
subsystem blocks on Cx power rail. Each client needs to set their
bit in tcsr register if it is going to cross its own threshold.
If all clients are going to cross their thresholds then Cx ipeak
hw module will raise an interrupt to cDSP block to throttle cDSP fmax.
config QCOM_SOC_WATCHDOG
tristate "Qualcomm Technologies, Inc. Soc Watchdog"
depends on QCOM_WDT_CORE

View file

@ -109,6 +109,7 @@ endif
obj-$(CONFIG_QTI_SYS_PM_VX) += sys_pm_vx.o
obj-$(CONFIG_ICNSS2) += icnss2/
obj-$(CONFIG_QTI_PLH_SCMI_CLIENT) += plh_scmi.o
obj-$(CONFIG_QCOM_SYSMON_SUBSYSTEM_STATS) += sysmon_subsystem_stats.o
obj-$(CONFIG_QTI_HW_MEMLAT_SCMI_CLIENT) += memlat_scmi.o
obj-$(CONFIG_QTI_HW_MEMLAT) += rimps_memlat.o
obj-$(CONFIG_QTI_HW_MEMLAT_LOG) += rimps_log.o
@ -120,6 +121,7 @@ obj-$(CONFIG_MSM_SLATECOM_INTERFACE) += slatecom_interface.o
obj-$(CONFIG_QCOM_AOP_SET_DDR) += aop-set-ddr.o
obj-$(CONFIG_CPU_V7) += idle-v7.o
obj-$(CONFIG_DUMP_XBL_LOG) += dump_boot_log.o
obj-$(CONFIG_QCOM_CX_IPEAK) += cx_ipeak.o
# GNSS driver
obj-$(CONFIG_GNSS_SIRF) += gnsssirf/
obj-$(CONFIG_MSM_SEB) += slate_events_bridge.o

545
drivers/soc/qcom/cx_ipeak.c Normal file
View file

@ -0,0 +1,545 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/printk.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <soc/qcom/cx_ipeak.h>
#define TCSR_CXIP_LM_VOTE_FEATURE_ENABLE_OFFSET 0x10
/* v1 register set */
#define TCSR_CXIP_LM_VOTE_BYPASS_OFFSET 0x4
#define TCSR_CXIP_LM_VOTE_CLEAR_OFFSET 0x8
#define TCSR_CXIP_LM_VOTE_SET_OFFSET 0xC
#define TCSR_CXIP_LM_TRS_OFFSET 0x24
/* v2 register set */
#define TCSR_CXIP_LM_VOTE_CLIENTx_BYPASS_OFFSET 0x4
#define TCSR_CXIP_LM_DANGER_OFFSET 0x24
#define CXIP_CLIENT_OFFSET 0x1000
#define CXIP_CLIENT10_OFFSET 0x3000
#define CXIP_VICTIM_OFFSET 0xB000
#define CXIP_POLL_TIMEOUT_US (50 * 1000)
#define CXIP_VICTIMS 3
#define VICTIM_ENTRIES 3
struct cx_ipeak_client;
struct cx_ipeak_core_ops {
int (*update)(struct cx_ipeak_client *client, bool vote);
struct cx_ipeak_client* (*register_client)(int client_id);
};
static struct cx_ipeak_victims {
u32 client_id;
u32 victim_id;
u32 freq_limit;
void *data;
cx_ipeak_victim_fn victim_cb;
struct cx_ipeak_client *client;
} victim_list[CXIP_VICTIMS];
static struct cx_ipeak_device {
struct platform_device *pdev;
struct mutex vote_lock;
struct mutex throttle_lock;
void __iomem *tcsr_vptr;
struct cx_ipeak_core_ops *core_ops;
u32 victims_count;
int danger_intr_num;
int safe_intr_num;
} device_ipeak;
struct cx_ipeak_client {
u32 vote_count;
unsigned int offset;
u32 client_id;
bool danger_assert;
struct cx_ipeak_device *dev;
};
/**
* cx_ipeak_register() - allocate client structure and fill device private and
* offset details.
* @dev_node: device node of the client
* @client_name: property name of the client
*
* Allocate client memory and fill the structure with device private and bit
*
*/
struct cx_ipeak_client *cx_ipeak_register(struct device_node *dev_node,
const char *client_name)
{
struct of_phandle_args cx_spec;
struct cx_ipeak_client *client = NULL;
int ret;
ret = of_parse_phandle_with_args(dev_node, client_name,
"#size-cells", 0, &cx_spec);
if (ret)
return ERR_PTR(-EINVAL);
if (!of_device_is_available(cx_spec.np))
return NULL;
if (device_ipeak.tcsr_vptr == NULL)
return ERR_PTR(-EPROBE_DEFER);
if (cx_spec.args[0] > 31)
return ERR_PTR(-EINVAL);
if (device_ipeak.core_ops)
client = device_ipeak.core_ops->register_client
(cx_spec.args[0]);
client->client_id = cx_spec.args[0];
return client;
}
EXPORT_SYMBOL(cx_ipeak_register);
static struct cx_ipeak_client *cx_ipeak_register_v1(int client_id)
{
struct cx_ipeak_client *client;
unsigned int reg_enable, reg_bypass;
void __iomem *vptr = device_ipeak.tcsr_vptr;
reg_enable = readl_relaxed(device_ipeak.tcsr_vptr +
TCSR_CXIP_LM_VOTE_FEATURE_ENABLE_OFFSET);
reg_bypass = readl_relaxed(vptr +
TCSR_CXIP_LM_VOTE_BYPASS_OFFSET) &
BIT(client_id);
if (!reg_enable || reg_bypass)
return NULL;
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client)
return ERR_PTR(-ENOMEM);
client->offset = BIT(client_id);
client->dev = &device_ipeak;
return client;
}
static struct cx_ipeak_client *cx_ipeak_register_v2(int client_id)
{
unsigned int reg_bypass, reg_enable;
struct cx_ipeak_client *client;
unsigned int client_offset = 0;
void __iomem *vptr = device_ipeak.tcsr_vptr;
int i;
for (i = 0; i <= client_id; i++)
client_offset += CXIP_CLIENT_OFFSET;
if (client_id >= 10)
client_offset += CXIP_CLIENT10_OFFSET;
reg_enable = readl_relaxed(device_ipeak.tcsr_vptr +
TCSR_CXIP_LM_VOTE_FEATURE_ENABLE_OFFSET);
reg_bypass = readl_relaxed(vptr + client_offset +
TCSR_CXIP_LM_VOTE_CLIENTx_BYPASS_OFFSET) &
BIT(0);
if (!reg_enable || reg_bypass)
return NULL;
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client)
return ERR_PTR(-ENOMEM);
client->offset = client_offset;
client->dev = &device_ipeak;
return client;
}
/**
* cx_ipeak_victim_register - victim registration API to handle
* the cx ipeak hw interrupts (danger/safe) to throttle freq.
* @client: cx ipeak client
* @victim_cb: callback function of victim
* @data: data to be passed to victim while handling irq
*/
int cx_ipeak_victim_register(struct cx_ipeak_client *client,
cx_ipeak_victim_fn victim_cb, void *data)
{
int i = 0;
if (!victim_cb)
return -EINVAL;
for (i = 0; i < device_ipeak.victims_count; i++)
if (client->client_id == victim_list[i].client_id) {
victim_list[i].victim_cb = victim_cb;
victim_list[i].data = data;
victim_list[i].client = client;
return 0;
}
return -ENOENT;
}
EXPORT_SYMBOL(cx_ipeak_victim_register);
/**
* cx_ipeak_victim_unregister - unregister victim client from
* cx_ipeak driver.
* @client: cx ipeak client
*/
void cx_ipeak_victim_unregister(struct cx_ipeak_client *client)
{
int i = 0;
for (i = 0; i < device_ipeak.victims_count; i++)
if (client->client_id == victim_list[i].client_id) {
victim_list[i].victim_cb = NULL;
victim_list[i].data = NULL;
victim_list[i].client = NULL;
}
}
EXPORT_SYMBOL(cx_ipeak_victim_unregister);
/**
* cx_ipeak_update() - Set/Clear client vote for Cx iPeak limit
* manager to throttle cDSP.
* @client: client handle.
* @vote: True to set the vote and False for reset.
*
* Receives vote from each client and decides whether to throttle cDSP or not.
* This function is NOP for the targets which does not support TCSR Cx iPeak.
*/
int cx_ipeak_update(struct cx_ipeak_client *client, bool vote)
{
/* Check for client and device availability and proceed */
if (!client)
return 0;
if (!client->dev || !client->dev->core_ops || !client->dev->tcsr_vptr)
return -EINVAL;
return client->dev->core_ops->update(client, vote);
}
EXPORT_SYMBOL(cx_ipeak_update);
static int cx_ipeak_update_v1(struct cx_ipeak_client *client, bool vote)
{
unsigned int reg_val;
int ret = 0;
mutex_lock(&client->dev->vote_lock);
if (vote) {
if (client->vote_count == 0) {
writel_relaxed(client->offset,
client->dev->tcsr_vptr +
TCSR_CXIP_LM_VOTE_SET_OFFSET);
/*
* Do a dummy read to give enough time for TRS register
* to become 1 when the last client votes.
*/
readl_relaxed(client->dev->tcsr_vptr +
TCSR_CXIP_LM_TRS_OFFSET);
ret = readl_poll_timeout(client->dev->tcsr_vptr +
TCSR_CXIP_LM_TRS_OFFSET,
reg_val, !reg_val, 0,
CXIP_POLL_TIMEOUT_US);
if (ret) {
writel_relaxed(client->offset,
client->dev->tcsr_vptr +
TCSR_CXIP_LM_VOTE_CLEAR_OFFSET);
goto done;
}
}
client->vote_count++;
} else {
if (client->vote_count > 0) {
client->vote_count--;
if (client->vote_count == 0) {
writel_relaxed(client->offset,
client->dev->tcsr_vptr +
TCSR_CXIP_LM_VOTE_CLEAR_OFFSET);
}
} else
ret = -EINVAL;
}
done:
mutex_unlock(&client->dev->vote_lock);
return ret;
}
static int cx_ipeak_update_v2(struct cx_ipeak_client *client, bool vote)
{
u32 reg_val;
int ret = 0;
mutex_lock(&client->dev->vote_lock);
if (vote) {
if (client->vote_count == 0) {
writel_relaxed(BIT(0),
client->dev->tcsr_vptr +
client->offset);
ret = readl_poll_timeout(
client->dev->tcsr_vptr +
TCSR_CXIP_LM_DANGER_OFFSET,
reg_val, !reg_val ||
client->danger_assert,
0, CXIP_POLL_TIMEOUT_US);
/*
* If poll exits due to danger assert condition return
* error to client to avoid voting.
*/
if (client->danger_assert)
ret = -ETIMEDOUT;
if (ret) {
writel_relaxed(0,
client->dev->tcsr_vptr +
client->offset);
goto done;
}
}
client->vote_count++;
} else {
if (client->vote_count > 0) {
client->vote_count--;
if (client->vote_count == 0) {
writel_relaxed(0,
client->dev->tcsr_vptr +
client->offset);
}
} else {
ret = -EINVAL;
}
}
done:
mutex_unlock(&client->dev->vote_lock);
return ret;
}
static irqreturn_t cx_ipeak_irq_soft_handler(int irq, void *data)
{
int i;
irqreturn_t ret = IRQ_NONE;
mutex_lock(&device_ipeak.throttle_lock);
for (i = 0; i < device_ipeak.victims_count; i++) {
cx_ipeak_victim_fn victim_cb = victim_list[i].victim_cb;
struct cx_ipeak_client *victim_client = victim_list[i].client;
if (!victim_cb || !victim_client)
continue;
if (irq == device_ipeak.danger_intr_num) {
victim_client->danger_assert = true;
/*
* To set frequency limit at victim client
* side in danger interrupt case
*/
ret = victim_cb(victim_list[i].data,
victim_list[i].freq_limit);
if (ret) {
dev_err(&device_ipeak.pdev->dev,
"Unable to throttle client:%d freq:%d\n",
victim_list[i].client_id,
victim_list[i].freq_limit);
victim_client->danger_assert = false;
ret = IRQ_HANDLED;
goto done;
}
writel_relaxed(1, (device_ipeak.tcsr_vptr +
CXIP_VICTIM_OFFSET +
((victim_list[i].victim_id)*
CXIP_CLIENT_OFFSET)));
ret = IRQ_HANDLED;
} else if (irq == device_ipeak.safe_intr_num) {
victim_client->danger_assert = false;
/*
* To remove frequency limit at victim client
* side in safe interrupt case
*/
ret = victim_cb(victim_list[i].data, 0);
if (ret)
dev_err(&device_ipeak.pdev->dev, "Unable to remove freq limit client:%d\n",
victim_list[i].client_id);
writel_relaxed(0, (device_ipeak.tcsr_vptr +
CXIP_VICTIM_OFFSET +
((victim_list[i].victim_id)*
CXIP_CLIENT_OFFSET)));
ret = IRQ_HANDLED;
}
}
done:
mutex_unlock(&device_ipeak.throttle_lock);
return ret;
}
int cx_ipeak_request_irq(struct platform_device *pdev, const char *name,
irq_handler_t handler, irq_handler_t thread_fn, void *data)
{
int ret, num = platform_get_irq_byname(pdev, name);
if (num < 0)
return num;
ret = devm_request_threaded_irq(&pdev->dev, num, handler, thread_fn,
IRQF_ONESHOT | IRQF_TRIGGER_RISING, name, data);
if (ret)
dev_err(&pdev->dev, "Unable to get interrupt %s: %d\n",
name, ret);
return ret ? ret : num;
}
/**
* cx_ipeak_unregister() - unregister client
* @client: client address to free
*
* Free the client memory
*/
void cx_ipeak_unregister(struct cx_ipeak_client *client)
{
kfree(client);
}
EXPORT_SYMBOL(cx_ipeak_unregister);
struct cx_ipeak_core_ops core_ops_v1 = {
.update = cx_ipeak_update_v1,
.register_client = cx_ipeak_register_v1,
};
struct cx_ipeak_core_ops core_ops_v2 = {
.update = cx_ipeak_update_v2,
.register_client = cx_ipeak_register_v2,
};
static int cx_ipeak_probe(struct platform_device *pdev)
{
struct resource *res;
int i, ret, count;
u32 victim_en;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
device_ipeak.tcsr_vptr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(device_ipeak.tcsr_vptr))
return PTR_ERR(device_ipeak.tcsr_vptr);
if (of_device_is_compatible(pdev->dev.of_node, "qcom,cx-ipeak-v1"))
device_ipeak.core_ops = &core_ops_v1;
else if (of_device_is_compatible(pdev->dev.of_node,
"qcom,cx-ipeak-v2"))
device_ipeak.core_ops = &core_ops_v2;
else
device_ipeak.core_ops = NULL;
victim_en = of_property_read_bool(pdev->dev.of_node,
"victims_table");
if (victim_en) {
count = of_property_count_u32_elems(pdev->dev.of_node,
"victims_table");
if (((count%VICTIM_ENTRIES) != 0) ||
((count/VICTIM_ENTRIES) > CXIP_VICTIMS))
return -EINVAL;
for (i = 0; i < (count/VICTIM_ENTRIES); i++) {
ret = of_property_read_u32_index(pdev->dev.of_node,
"victims_table", i*VICTIM_ENTRIES,
&victim_list[i].client_id);
if (ret)
return ret;
ret = of_property_read_u32_index(pdev->dev.of_node,
"victims_table", (i*VICTIM_ENTRIES) + 1,
&victim_list[i].victim_id);
if (ret)
return ret;
ret = of_property_read_u32_index(pdev->dev.of_node,
"victims_table", (i*VICTIM_ENTRIES) + 2,
&victim_list[i].freq_limit);
if (ret)
return ret;
device_ipeak.victims_count++;
}
device_ipeak.danger_intr_num = cx_ipeak_request_irq(pdev,
"cx_ipeak_danger", NULL,
cx_ipeak_irq_soft_handler, NULL);
if (device_ipeak.danger_intr_num < 0)
return device_ipeak.danger_intr_num;
device_ipeak.safe_intr_num = cx_ipeak_request_irq(pdev,
"cx_ipeak_safe", NULL,
cx_ipeak_irq_soft_handler, NULL);
if (device_ipeak.safe_intr_num < 0)
return device_ipeak.safe_intr_num;
}
device_ipeak.pdev = pdev;
mutex_init(&device_ipeak.vote_lock);
mutex_init(&device_ipeak.throttle_lock);
return 0;
}
static const struct of_device_id cx_ipeak_match_table[] = {
{ .compatible = "qcom,cx-ipeak-v1"},
{ .compatible = "qcom,cx-ipeak-v2"},
{}
};
static struct platform_driver cx_ipeak_platform_driver = {
.probe = cx_ipeak_probe,
.driver = {
.name = "cx_ipeak",
.of_match_table = cx_ipeak_match_table,
.suppress_bind_attrs = true,
}
};
static int __init cx_ipeak_init(void)
{
return platform_driver_register(&cx_ipeak_platform_driver);
}
arch_initcall(cx_ipeak_init);
MODULE_LICENSE("GPL v2");

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/delay.h>
@ -26,6 +26,7 @@ static struct icnss_vreg_cfg icnss_adrestea_vreg_list[] = {
{"vdd-1.3-rfa", 1304000, 1304000, 0, 0, 0, false, true},
{"vdd-3.3-ch1", 3312000, 3312000, 0, 0, 0, false, true},
{"vdd-3.3-ch0", 3312000, 3312000, 0, 0, 0, false, true},
{"vdd-smps", 984000, 984000, 0, 0, 0, false, true},
};
static struct icnss_clk_cfg icnss_clk_list[] = {

View file

@ -1350,6 +1350,10 @@ int wlfw_wlan_mode_send_sync_msg(struct icnss_priv *priv,
mode == QMI_WLFW_OFF_V01)
return 0;
if (!test_bit(ICNSS_MODE_ON, &priv->state) &&
mode == QMI_WLFW_OFF_V01)
return 0;
icnss_pr_dbg("Sending Mode request, state: 0x%lx, mode: %d\n",
priv->state, mode);

View file

@ -49,6 +49,7 @@ static bool is_rpm_controller;
static bool has_pend_offline_req;
static atomic_long_t totalram_pages_with_offline = ATOMIC_INIT(0);
static struct workqueue_struct *migrate_wq;
static unsigned long movable_bitmap;
#define MODULE_CLASS_NAME "mem-offline"
#define MIGRATE_TIMEOUT_SEC (20)
@ -752,6 +753,63 @@ static int mem_event_callback(struct notifier_block *self,
return NOTIFY_OK;
}
static int update_movable_bitmap(void)
{
struct device_node *node;
struct property *prop;
int len, num_cells, num_entries;
u64 base, size, end, section_size;
u64 movable_start, movable_end;
int nr_address_cells, nr_size_cells;
const __be32 *pos;
node = of_find_node_by_name(of_root, "memory");
if (!node) {
pr_err("mem-offine: memory node not found in DT\n");
return -EINVAL;
}
nr_address_cells = of_n_addr_cells(of_root);
nr_size_cells = of_n_size_cells(of_root);
prop = of_find_property(node, "reg", &len);
num_cells = len / sizeof(__be32);
num_entries = num_cells / (nr_address_cells + nr_size_cells);
pos = prop->value;
section_size = MIN_MEMORY_BLOCK_SIZE;
movable_start = memblock_end_of_DRAM();
movable_end = bootloader_memory_limit - 1;
while (num_entries--) {
u64 new_base, new_end;
u64 new_start_bitmap, bitmap_size;
base = of_read_number(pos, nr_address_cells);
size = of_read_number(pos + nr_address_cells, nr_size_cells);
pos += nr_address_cells + nr_size_cells;
end = base + size;
if (end <= movable_start)
continue;
if (base < movable_start)
new_base = movable_start;
else
new_base = base;
new_end = end;
new_start_bitmap = (new_base - movable_start) / section_size;
bitmap_size = (new_end - new_base) / section_size;
bitmap_set(&movable_bitmap, new_start_bitmap, bitmap_size);
}
pr_debug("mem-offline: movable_bitmap is %lx\n", movable_bitmap);
return 0;
}
static int mem_online_remaining_blocks(void)
{
unsigned long memblock_end_pfn = __phys_to_pfn(memblock_end_of_DRAM());
@ -760,6 +818,7 @@ static int mem_online_remaining_blocks(void)
unsigned int nid;
phys_addr_t phys_addr;
int fail = 0;
int ret;
block_size = memory_block_size_bytes();
sections_per_block = block_size / MIN_MEMORY_BLOCK_SIZE;
@ -771,8 +830,17 @@ static int mem_online_remaining_blocks(void)
pr_info("mem-offline: System booted with no zone movable memory blocks. Cannot perform memory offlining\n");
return -EINVAL;
}
ret = update_movable_bitmap();
if (ret < 0)
return -ENODEV;
for (memblock = start_section_nr; memblock <= end_section_nr;
memblock += sections_per_block) {
if (!test_bit(memblock - start_section_nr, &movable_bitmap))
continue;
pfn = section_nr_to_pfn(memblock);
phys_addr = __pfn_to_phys(pfn);

View file

@ -0,0 +1,89 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/soc/qcom/smem.h>
#include <linux/soc/qcom/sysmon_subsystem_stats.h>
#define SYSMON_SMEM_ID 634
#define SYSMON_POWER_STATS_VERSIONID 0x1
#define SYSMON_POWER_STATS_FEATUREID 0x3
/**
* sysmon_stats_query_power_residency() - * API to query requested
* DSP subsystem power residency.On success, returns power residency
* statistics in the given sysmon_smem_power_stats structure.
*/
int sysmon_stats_query_power_residency(enum dsp_id_t dsp_id,
struct sysmon_smem_power_stats *sysmon_power_stats)
{
u32 featureId;
int err = 0;
int feature, size_rcvd;
size_t size;
char *smem_pointer = NULL;
int size_of_u32 = sizeof(u32);
if (!sysmon_power_stats || !dsp_id) {
pr_err("%s: Null pointer received/invalid dsp ID\n", __func__);
return -EINVAL;
}
smem_pointer = qcom_smem_get(dsp_id, SYSMON_SMEM_ID, &size);
if (IS_ERR_OR_NULL(smem_pointer) || !size) {
pr_err("Failed to fetch data from SMEM for ID %d: %d\n",
dsp_id, PTR_ERR(smem_pointer));
return -ENOMEM;
}
featureId = *(unsigned int *)smem_pointer;
feature = featureId >> 28;
size_rcvd = (featureId >> 16) & 0xFFF;
while (size != 0) {
switch (feature) {
case SYSMON_POWER_STATS_FEATUREID:
if (!IS_ERR_OR_NULL(smem_pointer + size_of_u32)) {
memcpy(sysmon_power_stats, (smem_pointer + size_of_u32),
sizeof(struct sysmon_smem_power_stats));
size = 0;
} else {
pr_err("%s: Requested feature not found\n", __func__);
size = 0;
return -ENOMEM;
}
break;
default:
if (!IS_ERR_OR_NULL(smem_pointer + size_rcvd)
&& (size > size_rcvd)) {
featureId = *(unsigned int *)(smem_pointer + size_rcvd);
smem_pointer += size_rcvd;
size = size - size_rcvd;
feature = featureId >> 28;
size_rcvd = (featureId >> 16) & 0xFFF;
} else {
pr_err("%s: Requested feature not found\n", __func__);
size = 0;
return -ENOMEM;
}
break;
}
}
return err;
}
EXPORT_SYMBOL(sysmon_stats_query_power_residency);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Sysmon subsystem Stats driver");

View file

@ -30,6 +30,7 @@
/* UART specific GENI registers */
#define SE_UART_LOOPBACK_CFG (0x22C)
#define SE_GENI_CFG_REG80 (0x240)
#define SE_UART_TX_TRANS_CFG (0x25C)
#define SE_UART_TX_WORD_LEN (0x268)
#define SE_UART_TX_STOP_BIT_LEN (0x26C)
@ -258,6 +259,7 @@ static int msm_geni_serial_runtime_resume(struct device *dev);
static int msm_geni_serial_runtime_suspend(struct device *dev);
static int msm_geni_serial_get_ver_info(struct uart_port *uport);
static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport);
static void msm_geni_serial_allow_rx(struct msm_geni_serial_port *port);
static int uart_line_id;
#define GET_DEV_PORT(uport) \
@ -308,6 +310,7 @@ static void msm_geni_update_uart_error_code(struct msm_geni_serial_port *port,
static void msm_geni_serial_enable_interrupts(struct uart_port *uport)
{
unsigned int geni_m_irq_en, geni_s_irq_en;
unsigned int geni_dma_tx_irq_en, geni_dma_rx_irq_en;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
geni_m_irq_en = geni_read_reg_nolog(uport->membase,
@ -326,12 +329,28 @@ static void msm_geni_serial_enable_interrupts(struct uart_port *uport)
geni_write_reg_nolog(DMA_RX_IRQ_BITS, uport->membase,
SE_DMA_RX_IRQ_EN_SET);
}
if (!uart_console(uport)) {
geni_m_irq_en = geni_read_reg_nolog(uport->membase,
SE_GENI_M_IRQ_EN);
geni_s_irq_en = geni_read_reg_nolog(uport->membase,
SE_GENI_S_IRQ_EN);
geni_dma_tx_irq_en = geni_read_reg_nolog(uport->membase,
SE_DMA_TX_IRQ_EN);
geni_dma_rx_irq_en = geni_read_reg_nolog(uport->membase,
SE_DMA_RX_IRQ_EN);
IPC_LOG_MSG(port->ipc_log_misc,
"%s: M_IRQ_EN:0x%x S_IRQ_EN:0x%x TX_IRQ_EN:0x%x RX_IRQ_EN:0x%x\n",
__func__, geni_m_irq_en, geni_s_irq_en,
geni_dma_tx_irq_en, geni_dma_rx_irq_en);
}
}
/* Try disabling interrupts in order to do polling in an atomic contexts. */
static bool msm_serial_try_disable_interrupts(struct uart_port *uport)
{
unsigned int geni_m_irq_en, geni_s_irq_en;
unsigned int geni_dma_tx_irq_en, geni_dma_rx_irq_en;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
/*
@ -356,6 +375,21 @@ static bool msm_serial_try_disable_interrupts(struct uart_port *uport)
SE_DMA_RX_IRQ_EN_CLR);
}
if (!uart_console(uport)) {
geni_m_irq_en = geni_read_reg_nolog(uport->membase,
SE_GENI_M_IRQ_EN);
geni_s_irq_en = geni_read_reg_nolog(uport->membase,
SE_GENI_S_IRQ_EN);
geni_dma_tx_irq_en = geni_read_reg_nolog(uport->membase,
SE_DMA_TX_IRQ_EN);
geni_dma_rx_irq_en = geni_read_reg_nolog(uport->membase,
SE_DMA_RX_IRQ_EN);
IPC_LOG_MSG(port->ipc_log_misc,
"%s: M_IRQ_EN:0x%x S_IRQ_EN:0x%x TX_IRQ_EN:0x%x RX_IRQ_EN:0x%x\n",
__func__, geni_m_irq_en, geni_s_irq_en,
geni_dma_tx_irq_en, geni_dma_rx_irq_en);
}
return true;
}
@ -375,6 +409,8 @@ static bool geni_wait_for_cmd_done(struct uart_port *uport, bool is_irq_masked)
* We need to do polling if spinlock is taken
* by framework as we cannot rely on ISR.
*/
if (!uart_console(uport))
IPC_LOG_MSG(msm_port->ipc_log_misc, "%s polling:%d\n", __func__, is_irq_masked);
if (is_irq_masked) {
/*
* Polling is done for 1000 iterrations with
@ -1028,6 +1064,9 @@ static void msm_geni_serial_console_write(struct console *co, const char *s,
"%s: tx abort failed 0x%x\n", __func__,
geni_read_reg_nolog(uport->membase,
SE_GENI_STATUS));
msm_geni_serial_allow_rx(port);
geni_write_reg(FORCE_DEFAULT, uport->membase,
GENI_FORCE_DEFAULT_REG);
}
msm_geni_serial_enable_interrupts(uport);
@ -1181,6 +1220,9 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport)
SE_GENI_STATUS));
msm_geni_update_uart_error_code(msm_port, UART_ERROR_TX_ABORT_FAIL);
}
msm_geni_serial_allow_rx(msm_port);
geni_write_reg(FORCE_DEFAULT, uport->membase,
GENI_FORCE_DEFAULT_REG);
}
if (msm_port->xfer_mode == SE_DMA) {
@ -1225,6 +1267,13 @@ static void msm_geni_serial_start_tx(struct uart_port *uport)
unsigned int geni_ios;
static unsigned int ios_log_limit;
/* when start_tx is called with UART clocks OFF return. */
if (uart_console(uport) && msm_port->is_clock_off) {
IPC_LOG_MSG(msm_port->console_log,
"%s. Console in suspend state\n", __func__);
return;
}
if (!uart_console(uport) && !pm_runtime_active(uport->dev)) {
IPC_LOG_MSG(msm_port->ipc_log_misc,
"%s.Putting in async RPM vote\n", __func__);
@ -1328,6 +1377,9 @@ static void stop_tx_sequencer(struct uart_port *uport)
geni_read_reg_nolog(uport->membase, SE_GENI_STATUS));
msm_geni_update_uart_error_code(port, UART_ERROR_TX_ABORT_FAIL);
}
msm_geni_serial_allow_rx(port);
geni_write_reg(FORCE_DEFAULT, uport->membase,
GENI_FORCE_DEFAULT_REG);
}
if (port->xfer_mode == SE_DMA) {
@ -1608,6 +1660,9 @@ static int stop_rx_sequencer(struct uart_port *uport)
geni_se_dump_dbg_regs(&port->serial_rsc,
uport->membase, port->ipc_log_misc);
}
msm_geni_serial_allow_rx(port);
geni_write_reg(FORCE_DEFAULT, uport->membase,
GENI_FORCE_DEFAULT_REG);
if (port->xfer_mode == SE_DMA) {
port->s_cmd_done = false;
@ -2168,9 +2223,9 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport,
if (m_irq_status || s_irq_status ||
dma_tx_status || dma_rx_status)
IPC_LOG_MSG(msm_port->ipc_log_irqstatus,
"%s: sirq:0x%x mirq:0x%x dma_txirq:0x%x dma_rxirq:0x%x\n",
"%s: sirq:0x%x mirq:0x%x dma_txirq:0x%x dma_rxirq:0x%x is_irq_masked:%d\n",
__func__, s_irq_status, m_irq_status,
dma_tx_status, dma_rx_status);
dma_tx_status, dma_rx_status, is_irq_masked);
m_cmd_done = handle_tx_dma_xfer(m_irq_status, uport);
s_cmd_done = handle_rx_dma_xfer(s_irq_status, uport);
}
@ -2351,6 +2406,8 @@ static int msm_geni_serial_port_setup(struct uart_port *uport)
SE_GENI_RX_PACKING_CFG0);
geni_write_reg_nolog(cfg1, uport->membase,
SE_GENI_RX_PACKING_CFG1);
geni_write_reg_nolog(0x431c, uport->membase,
SE_GENI_CFG_REG80);
if (!msm_port->rx_fifo) {
ret = -ENOMEM;
goto exit_portsetup;
@ -2618,7 +2675,10 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
}
if (!uart_console(uport)) {
int ret = msm_geni_serial_power_on(uport);
int ret;
IPC_LOG_MSG(port->ipc_log_misc, "%s: start\n", __func__);
ret = msm_geni_serial_power_on(uport);
if (ret) {
IPC_LOG_MSG(port->ipc_log_misc,
@ -3562,6 +3622,7 @@ static int msm_geni_serial_sys_suspend(struct device *dev)
if (uart_console(uport) || port->pm_auto_suspend_disable) {
uart_suspend_port((struct uart_driver *)uport->private_data,
uport);
IPC_LOG_MSG(port->console_log, "%s\n", __func__);
} else {
struct uart_state *state = uport->state;
struct tty_port *tty_port = &state->port;
@ -3593,6 +3654,7 @@ static int msm_geni_serial_sys_resume(struct device *dev)
port->pm_auto_suspend_disable) {
uart_resume_port((struct uart_driver *)uport->private_data,
uport);
IPC_LOG_MSG(port->console_log, "%s\n", __func__);
}
return 0;
}

View file

@ -71,12 +71,6 @@ struct aio_ring {
struct io_event io_events[0];
}; /* 128 bytes + ring size */
/*
* Plugging is meant to work with larger batches of IOs. If we don't
* have more than the below, then don't bother setting up a plug.
*/
#define AIO_PLUG_THRESHOLD 2
#define AIO_RING_PAGES 8
struct kioctx_table {
@ -1932,8 +1926,7 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
if (nr > ctx->nr_events)
nr = ctx->nr_events;
if (nr > AIO_PLUG_THRESHOLD)
blk_start_plug(&plug);
blk_start_plug(&plug);
for (i = 0; i < nr; i++) {
struct iocb __user *user_iocb;
@ -1946,8 +1939,7 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
if (ret)
break;
}
if (nr > AIO_PLUG_THRESHOLD)
blk_finish_plug(&plug);
blk_finish_plug(&plug);
percpu_ref_put(&ctx->users);
return i ? i : ret;
@ -1974,8 +1966,7 @@ COMPAT_SYSCALL_DEFINE3(io_submit, compat_aio_context_t, ctx_id,
if (nr > ctx->nr_events)
nr = ctx->nr_events;
if (nr > AIO_PLUG_THRESHOLD)
blk_start_plug(&plug);
blk_start_plug(&plug);
for (i = 0; i < nr; i++) {
compat_uptr_t user_iocb;
@ -1988,8 +1979,7 @@ COMPAT_SYSCALL_DEFINE3(io_submit, compat_aio_context_t, ctx_id,
if (ret)
break;
}
if (nr > AIO_PLUG_THRESHOLD)
blk_finish_plug(&plug);
blk_finish_plug(&plug);
percpu_ref_put(&ctx->users);
return i ? i : ret;

2
fs/fuse/OWNERS Normal file
View file

@ -0,0 +1,2 @@
# include OWNERS from the authoritative android-mainline branch
include kernel/common:android-mainline:/fs/fuse/OWNERS

View file

@ -549,7 +549,6 @@ int incfs_read_file_header(struct backing_file_context *bfc,
if (!bfc || !first_md_off)
return -EFAULT;
LOCK_REQUIRED(bfc->bc_mutex);
bytes_read = incfs_kread(bfc, &fh, sizeof(fh), 0);
if (bytes_read < 0)
return bytes_read;

View file

@ -30,8 +30,18 @@ static ssize_t corefs_show(struct kobject *kobj,
static struct kobj_attribute corefs_attr = __ATTR_RO(corefs);
static ssize_t mounter_context_for_backing_rw_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
return snprintf(buff, PAGE_SIZE, "supported\n");
}
static struct kobj_attribute mounter_context_for_backing_rw_attr =
__ATTR_RO(mounter_context_for_backing_rw);
static struct attribute *attributes[] = {
&corefs_attr.attr,
&mounter_context_for_backing_rw_attr.attr,
NULL,
};

View file

@ -94,4 +94,9 @@
#define CAM_CPAS_RT_OT_FUSE 9
#define CAM_CPAS_FUSE_FEATURE_MAX 10
/* Flash type*/
#define CAM_FLASH_TYPE_GPIO 0
#define CAM_FLASH_TYPE_I2C 1
#define CAM_FLASH_TYPE_PMIC 2
#endif

52
include/linux/msm_kgsl.h Normal file
View file

@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_KGSL_H
#define _MSM_KGSL_H
/**
* struct kgsl_gpu_freq_stat - Per GPU freq stat struct
* @freq: GPU frequency in Hz
* @active_time: GPU busy time in usecs
* @idle_time: GPU idle time in usec
*/
struct kgsl_gpu_freq_stat {
u32 freq;
u64 active_time;
u64 idle_time;
};
/**
* kgsl_gpu_num_freqs - Get number of available GPU frequencies
*
* Return: number of available frequencies on success or negative error
* on failure
*/
int kgsl_gpu_num_freqs(void);
/**
* kgsl_gpu_stat - Get per GPU freq stats
* @stats: Array of struct kgsl_gpu_freq_stat to hold stats
* @numfreq: Number of entries in @stats
*
* This function will populate @stats with per freq stats.
* Number of entries in @stats array must be greater or
* equal to value returned by function kgsl_gpu_num_freqs
*
* Return: 0 on success or negative error on failure
*/
int kgsl_gpu_stat(struct kgsl_gpu_freq_stat *stats, u32 numfreq);
/**
* kgsl_gpu_frame_count - Get number of frames already processed by GPU
* @pid: pid of the process for which frame count is required
* @frame_count: pointer to a u64 to store frame count
*
* Return: zero on success and number of frames processed corresponding
* to @pid in @frame_count or negative error on failure
*/
int kgsl_gpu_frame_count(pid_t pid, u64 *frame_count);
#endif /* _MSM_KGSL_H */

View file

@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*/
/*
* This header is for sysmon subsystem stats query API's in drivers.
*/
#ifndef __QCOM_SYSMON_SUBSYSTEM_STATS_H__
#define __QCOM_SYSMON_SUBSYSTEM_STATS_H__
/*
* @struct sysmon_smem_power_stats_t
* @brief Structure type to hold DSP power statistics.
*/
struct sysmon_smem_power_stats {
u32 clk_arr[8];
/**< Core clock frequency(KHz) array */
u32 active_time[8];
/**< Active time(seconds) array corresponding to core clock array */
u32 pc_time;
/**< DSP LPM(Low Power Mode) time(seconds) */
u32 lpi_time;
/**< DSP LPI(Low Power Island Mode) time(seconds) */
};
/*
* @enum dsp_id_t
* @brief Enum to hold SMEM HOST ID for DSP subsystems.
*/
enum dsp_id_t {
ADSP = 2,
SLPI,
CDSP = 5
};
/**
* API to query requested DSP subsystem power residency.
* On success, returns power residency statistics in the given
* sysmon_smem_power_stats structure.
* @arg: DSP_ID
.* 2 - ADSP
* 3 - SLPI
* 5 - CDSP
*sysmon_smem_power_stats
* u32 clk_arr[8];
* u32 active_time[8];
* u32 pc_time;
* u32 lpi_time;
*@return SUCCESS (0) if Query is succssful
* FAILURE (Non-zero) if Query could not be processed.
*
*/
int sysmon_stats_query_power_residency(enum dsp_id_t dsp_id,
struct sysmon_smem_power_stats *sysmon_power_stats);
#endif

View file

@ -29,6 +29,7 @@ enum cnss_bus_width_type {
enum cnss_platform_cap_flag {
CNSS_HAS_EXTERNAL_SWREG = 0x01,
CNSS_HAS_UART_ACCESS = 0x02,
CNSS_HAS_DRV_SUPPORT = 0x04,
};
struct cnss_platform_cap {

View file

@ -171,7 +171,7 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
int udp_gro_complete(struct sk_buff *skb, int nhoff, udp_lookup_t lookup);
struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
netdev_features_t features);
netdev_features_t features, bool is_ipv6);
static inline struct udphdr *udp_gro_udphdr(struct sk_buff *skb)
{

View file

@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018, 2021 The Linux Foundation. All rights reserved.
*/
#ifndef __SOC_COM_CX_IPEAK_H
#define __SOC_COM_CX_IPEAK_H
typedef int (*cx_ipeak_victim_fn)(void *data, u32 freq_limit);
struct device_node;
struct cx_ipeak_client;
#if IS_ENABLED(CONFIG_QCOM_CX_IPEAK)
struct cx_ipeak_client *cx_ipeak_register(struct device_node *dev_node,
const char *client_name);
void cx_ipeak_unregister(struct cx_ipeak_client *client);
int cx_ipeak_update(struct cx_ipeak_client *ipeak_client, bool vote);
int cx_ipeak_victim_register(struct cx_ipeak_client *client,
cx_ipeak_victim_fn victim_cb, void *data);
void cx_ipeak_victim_unregister(struct cx_ipeak_client *client);
#else
static inline struct cx_ipeak_client *cx_ipeak_register(
struct device_node *dev_node,
const char *client_name)
{
return NULL;
}
static inline void cx_ipeak_unregister(struct cx_ipeak_client *client)
{
}
static inline int cx_ipeak_update(struct cx_ipeak_client *ipeak_client,
bool vote)
{
return 0;
}
static inline int cx_ipeak_victim_register(struct cx_ipeak_client *client,
cx_ipeak_victim_fn victim_cb, void *data)
{
return 0;
}
static inline void cx_ipeak_victim_unregister(struct cx_ipeak_client *client)
{
}
#endif
#endif /*__SOC_COM_CX_IPEAK_H*/

1
kernel/.gitignore vendored
View file

@ -1,6 +1,7 @@
#
# Generated files
#
config_data
kheaders.md5
timeconst.h
hz.bc

View file

@ -128,10 +128,15 @@ KCOV_INSTRUMENT_stackleak.o := n
$(obj)/configs.o: $(obj)/config_data.gz
targets += config_data.gz
$(obj)/config_data.gz: $(KCONFIG_CONFIG) FORCE
targets += config_data config_data.gz
$(obj)/config_data.gz: $(obj)/config_data FORCE
$(call if_changed,gzip)
filechk_cat = cat $<
$(obj)/config_data: $(KCONFIG_CONFIG) FORCE
$(call filechk,cat)
$(obj)/kheaders.o: $(obj)/kheaders_data.tar.xz
quiet_cmd_genikh = CHK $(obj)/kheaders_data.tar.xz

View file

@ -3870,6 +3870,9 @@ void scheduler_tick(void)
if (curr->sched_class == &fair_sched_class)
check_for_migration(rq, curr);
if (idle_cpu(cpu) && is_reserved(cpu))
clear_reserved(cpu);
trace_android_vh_scheduler_tick(rq);
}

View file

@ -6302,22 +6302,22 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int t
static int
select_idle_capacity(struct task_struct *p, struct sched_domain *sd, int target)
{
unsigned long best_cap = 0;
unsigned long task_util, best_cap = 0;
int cpu, best_cpu = -1;
struct cpumask *cpus;
sync_entity_load_avg(&p->se);
cpus = this_cpu_cpumask_var_ptr(select_idle_mask);
cpumask_and(cpus, sched_domain_span(sd), p->cpus_ptr);
task_util = uclamp_task_util(p);
for_each_cpu_wrap(cpu, cpus, target) {
unsigned long cpu_cap = capacity_of(cpu);
if ((!available_idle_cpu(cpu) && !sched_idle_cpu(cpu)) ||
cpu_isolated(target))
continue;
if (task_fits_capacity(p, cpu_cap, cpu))
if (fits_capacity(task_util, cpu_cap))
return cpu;
if (cpu_cap > best_cap) {
@ -6329,14 +6329,60 @@ select_idle_capacity(struct task_struct *p, struct sched_domain *sd, int target)
return best_cpu;
}
static inline bool asym_fits_capacity(int task_util, int cpu)
{
if (static_branch_unlikely(&sched_asym_cpucapacity))
return fits_capacity(task_util, capacity_of(cpu));
return true;
}
/*
* Try and locate an idle core/thread in the LLC cache domain.
*/
static int select_idle_sibling(struct task_struct *p, int prev, int target)
{
struct sched_domain *sd;
unsigned long task_util;
int i, recent_used_cpu;
/*
* On asymmetric system, update task utilization because we will check
* that the task fits with cpu's capacity.
*/
if (static_branch_unlikely(&sched_asym_cpucapacity)) {
sync_entity_load_avg(&p->se);
task_util = uclamp_task_util(p);
}
if ((available_idle_cpu(target) || sched_idle_cpu(target)) &&
asym_fits_capacity(task_util, target))
return target;
/*
* If the previous CPU is cache affine and idle, don't be stupid:
*/
if (prev != target && cpus_share_cache(prev, target) &&
(available_idle_cpu(prev) || sched_idle_cpu(prev)) &&
asym_fits_capacity(task_util, prev))
return prev;
/* Check a recently used CPU as a potential idle candidate: */
recent_used_cpu = p->recent_used_cpu;
if (recent_used_cpu != prev &&
recent_used_cpu != target &&
cpus_share_cache(recent_used_cpu, target) &&
(available_idle_cpu(recent_used_cpu) || sched_idle_cpu(recent_used_cpu)) &&
cpumask_test_cpu(p->recent_used_cpu, p->cpus_ptr) &&
asym_fits_capacity(task_util, recent_used_cpu)) {
/*
* Replace recent_used_cpu with prev as it is a potential
* candidate for the next wake:
*/
p->recent_used_cpu = prev;
return recent_used_cpu;
}
/*
* For asymmetric CPU capacity systems, our domain of interest is
* sd_asym_cpucapacity rather than sd_llc.
@ -6351,39 +6397,10 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
* SD_ASYM_CPUCAPACITY. These should follow the usual symmetric
* capacity path.
*/
if (!sd)
goto symmetric;
i = select_idle_capacity(p, sd, target);
return ((unsigned)i < nr_cpumask_bits) ? i : target;
}
symmetric:
if ((available_idle_cpu(target) || sched_idle_cpu(target)) &&
!cpu_isolated(target))
return target;
/*
* If the previous CPU is cache affine and idle, don't be stupid:
*/
if (prev != target && cpus_share_cache(prev, target) &&
((available_idle_cpu(prev) || sched_idle_cpu(prev)) &&
!cpu_isolated(prev)))
return prev;
/* Check a recently used CPU as a potential idle candidate: */
recent_used_cpu = p->recent_used_cpu;
if (recent_used_cpu != prev &&
recent_used_cpu != target &&
cpus_share_cache(recent_used_cpu, target) &&
(available_idle_cpu(recent_used_cpu) || sched_idle_cpu(recent_used_cpu)) &&
cpumask_test_cpu(p->recent_used_cpu, p->cpus_ptr)) {
/*
* Replace recent_used_cpu with prev as it is a potential
* candidate for the next wake:
*/
p->recent_used_cpu = prev;
return recent_used_cpu;
if (sd) {
i = select_idle_capacity(p, sd, target);
return ((unsigned)i < nr_cpumask_bits) ? i : target;
}
}
sd = rcu_dereference(per_cpu(sd_llc, target));

View file

@ -36,7 +36,6 @@
struct cma cma_areas[MAX_CMA_AREAS];
unsigned cma_area_count;
static DEFINE_MUTEX(cma_mutex);
phys_addr_t cma_get_base(const struct cma *cma)
{
@ -508,10 +507,9 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align,
mutex_unlock(&cma->lock);
pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit);
mutex_lock(&cma_mutex);
ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA,
GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0));
mutex_unlock(&cma_mutex);
if (ret == 0) {
page = pfn_to_page(pfn);
break;

View file

@ -92,6 +92,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_GSO_SCTP_BIT] = "tx-sctp-segmentation",
[NETIF_F_GSO_ESP_BIT] = "tx-esp-segmentation",
[NETIF_F_GSO_UDP_L4_BIT] = "tx-udp-segmentation",
[NETIF_F_GSO_FRAGLIST_BIT] = "tx-gso-list",
[NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc",
[NETIF_F_SCTP_CRC_BIT] = "tx-checksum-sctp",

View file

@ -3649,7 +3649,8 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
unsigned int delta_truesize = 0;
unsigned int delta_len = 0;
struct sk_buff *tail = NULL;
struct sk_buff *nskb;
struct sk_buff *nskb, *tmp;
int err;
skb_push(skb, -skb_network_offset(skb) + offset);
@ -3659,11 +3660,28 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
nskb = list_skb;
list_skb = list_skb->next;
err = 0;
if (skb_shared(nskb)) {
tmp = skb_clone(nskb, GFP_ATOMIC);
if (tmp) {
consume_skb(nskb);
nskb = tmp;
err = skb_unclone(nskb, GFP_ATOMIC);
} else {
err = -ENOMEM;
}
}
if (!tail)
skb->next = nskb;
else
tail->next = nskb;
if (unlikely(err)) {
nskb->next = list_skb;
goto err_linearize;
}
tail = nskb;
delta_len += nskb->len;

View file

@ -184,8 +184,67 @@ out_unlock:
}
EXPORT_SYMBOL(skb_udp_tunnel_segment);
static void __udpv4_gso_segment_csum(struct sk_buff *seg,
__be32 *oldip, __be32 *newip,
__be16 *oldport, __be16 *newport)
{
struct udphdr *uh;
struct iphdr *iph;
if (*oldip == *newip && *oldport == *newport)
return;
uh = udp_hdr(seg);
iph = ip_hdr(seg);
if (uh->check) {
inet_proto_csum_replace4(&uh->check, seg, *oldip, *newip,
true);
inet_proto_csum_replace2(&uh->check, seg, *oldport, *newport,
false);
if (!uh->check)
uh->check = CSUM_MANGLED_0;
}
*oldport = *newport;
csum_replace4(&iph->check, *oldip, *newip);
*oldip = *newip;
}
static struct sk_buff *__udpv4_gso_segment_list_csum(struct sk_buff *segs)
{
struct sk_buff *seg;
struct udphdr *uh, *uh2;
struct iphdr *iph, *iph2;
seg = segs;
uh = udp_hdr(seg);
iph = ip_hdr(seg);
if ((udp_hdr(seg)->dest == udp_hdr(seg->next)->dest) &&
(udp_hdr(seg)->source == udp_hdr(seg->next)->source) &&
(ip_hdr(seg)->daddr == ip_hdr(seg->next)->daddr) &&
(ip_hdr(seg)->saddr == ip_hdr(seg->next)->saddr))
return segs;
while ((seg = seg->next)) {
uh2 = udp_hdr(seg);
iph2 = ip_hdr(seg);
__udpv4_gso_segment_csum(seg,
&iph2->saddr, &iph->saddr,
&uh2->source, &uh->source);
__udpv4_gso_segment_csum(seg,
&iph2->daddr, &iph->daddr,
&uh2->dest, &uh->dest);
}
return segs;
}
static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
netdev_features_t features)
netdev_features_t features,
bool is_ipv6)
{
unsigned int mss = skb_shinfo(skb)->gso_size;
@ -195,11 +254,11 @@ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss);
return skb;
return is_ipv6 ? skb : __udpv4_gso_segment_list_csum(skb);
}
struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
netdev_features_t features)
netdev_features_t features, bool is_ipv6)
{
struct sock *sk = gso_skb->sk;
unsigned int sum_truesize = 0;
@ -211,7 +270,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
__be16 newlen;
if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST)
return __udp_gso_segment_list(gso_skb, features);
return __udp_gso_segment_list(gso_skb, features, is_ipv6);
mss = skb_shinfo(gso_skb)->gso_size;
if (gso_skb->len <= sizeof(*uh) + mss)
@ -325,7 +384,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
goto out;
if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
return __udp_gso_segment(skb, features);
return __udp_gso_segment(skb, features, false);
mss = skb_shinfo(skb)->gso_size;
if (unlikely(skb->len <= mss))

View file

@ -46,7 +46,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
goto out;
if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
return __udp_gso_segment(skb, features);
return __udp_gso_segment(skb, features, true);
/* Do software UFO. Complete and fill in the UDP checksum as HW cannot
* do checksum of UDP packets sent as multiple IP fragments.

View file

@ -234,6 +234,7 @@ static int xfrm_xlate64_attr(struct sk_buff *dst, const struct nlattr *src)
case XFRMA_PAD:
/* Ignore */
return 0;
case XFRMA_UNSPEC:
case XFRMA_ALG_AUTH:
case XFRMA_ALG_CRYPT:
case XFRMA_ALG_COMP:
@ -387,7 +388,7 @@ static int xfrm_attr_cpy32(void *dst, size_t *pos, const struct nlattr *src,
memcpy(nla, src, nla_attr_size(copy_len));
nla->nla_len = nla_attr_size(payload);
*pos += nla_attr_size(payload);
*pos += nla_attr_size(copy_len);
nlmsg->nlmsg_len += nla->nla_len;
memset(dst + *pos, 0, payload - copy_len);
@ -563,7 +564,7 @@ static struct nlmsghdr *xfrm_user_rcv_msg_compat(const struct nlmsghdr *h32,
return NULL;
len += NLMSG_HDRLEN;
h64 = kvmalloc(len, GFP_KERNEL | __GFP_ZERO);
h64 = kvmalloc(len, GFP_KERNEL);
if (!h64)
return ERR_PTR(-ENOMEM);

View file

@ -2381,8 +2381,10 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen
if (in_compat_syscall()) {
struct xfrm_translator *xtr = xfrm_get_translator();
if (!xtr)
if (!xtr) {
kfree(data);
return -EOPNOTSUPP;
}
err = xtr->xlate_user_policy_sockptr(&data, optlen);
xfrm_put_translator(xtr);

View file

@ -34,9 +34,6 @@ case "$KBUILD_VERBOSE" in
;;
esac
# We need access to CONFIG_ symbols
. include/config/auto.conf
# Generate a new symbol list file
$CONFIG_SHELL $srctree/scripts/gen_autoksyms.sh "$new_ksyms_file"