Merge tag 'LA.UM.9.14.r1-19600.01-LAHAINA.QSSI12.0' of https://git.codelinaro.org/clo/la/platform/vendor/opensource/dataipa into android12-5.4-lahaina

"LA.UM.9.14.r1-19600.01-LAHAINA.QSSI12.0"

* tag 'LA.UM.9.14.r1-19600.01-LAHAINA.QSSI12.0' of https://git.codelinaro.org/clo/la/platform/vendor/opensource/dataipa:
  msm: ipa3: Handle race condition to avoid NULL access
  msm: ipa3: Reduce the QMI timeout value to avoid race condition
  msm: ipa: Set the logbuf NULL after destroy
  msm: gsi: Fix the incorrect evt ring pointer
  msm: ipa3: In deep sleep scenario destroy/ reinitialize uC interrupts
  msm: ipa3: Changes to resume only suspend operation complete
  msm: ipa3: Disable gsi fifo and test bus registers
  msm: ipa3: Fix to validate the NAT table entries during NAT table init
  msm: ipa3: Fix to avoid the boot up crash in non smmu targets
  msm: ipa3: Disable of ODL offload checksum
  msm: ipa3: Deepsleep enable changes
  msm: ipa3: enable ipa register save when device is about to crash
  msm: ipa3: Changes not allow ODL pipe setup during SSR
  msm: ipa: use lower order pages
  msm: ipa3: fix to cleanup the dma allocation.
  msm: ipa: Get device pointers if smmu is disabled
  msm: gsi: Read 64-bit ring RP value from registers
  msm: ipa3: Retry to attach smmu nodes if fails
  msm: ipa: add skb recycle if dma fails during replenish
  msm: ipa: remove initing head again if dma mapping fails
  msm: ipa3: Retry to attach smmu nodes if fails
  msm: ipa3: Adding changes to support the deep sleep mode
  msm: ipa3: Fix to NULL terminate the header pointer in proc header table
  msm: ipa3: Pointer Check and Fix overflow in Header Deletion
  msm: ipa3: Queue nop desc again if it fails.
  msm: ipa3: increasing the uC interrupt timeout value
  msm: ipa3: Add wait queue for the adpl
  msm: ipa3: Add change to not reset HOLB timer
  msm: ipa3: Add retry attempts for subsystem loading
  msm: ipa: Fix to free up all pending EOB pages
  msm: ipa3: Fix null pointer dereference error
  msm: ipa3: Reduced excessive logs from ipa
  msm: ipa3: Configure HOLB for WLAN2 consumer pipe

Change-Id: I86cdd282a02be47a6653b009a1f400fe67160edc
This commit is contained in:
Michael Bestas 2022-05-24 09:15:49 +03:00
commit 8da1d33744
No known key found for this signature in database
GPG key ID: CC95044519BE6669
25 changed files with 638 additions and 107 deletions

View file

@ -1,10 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define CONFIG_GSI 1
#define CONFIG_GSI_REGISTER_VERSION_2 1
#define CONFIG_RMNET_IPA3 1
#define CONFIG_RNDIS_IPA 1
#define CONFIG_IPA_WDI_UNIFIED_API 1
#define CONFIG_IPA3_REGDUMP 1
#define CONFIG_IPA3_APPS_REGDUMP 1
#define CONFIG_IPA3_REGDUMP_IPA_4_5 1
#define CONFIG_IPA3_4_5_RGSTR 0
#define CONFIG_IPA3_REGDUMP_NUM_EXTRA_ENDP_REGS 0

View file

@ -4,3 +4,7 @@ export CONFIG_IPA_CLIENTS_MANAGER=m
export CONFIG_IPA_WDI_UNIFIED_API=y
export CONFIG_RMNET_IPA3=y
export CONFIG_RNDIS_IPA=m
export CONFIG_IPA3_REGDUMP=y
export CONFIG_IPA3_APPS_REGDUMP=y
export CONFIG_IPA3_REGDUMP_IPA_4_5=y
export CONFIG_IPA3_4_5_RGSTR=n

View file

@ -4,3 +4,7 @@ export CONFIG_IPA_CLIENTS_MANAGER=y
export CONFIG_IPA_WDI_UNIFIED_API=y
export CONFIG_RMNET_IPA3=y
export CONFIG_RNDIS_IPA=y
export CONFIG_IPA3_REGDUMP=y
export CONFIG_IPA3_APPS_REGDUMP=y
export CONFIG_IPA3_REGDUMP_IPA_4_5=y
export CONFIG_IPA3_4_5_RGSTR=n

View file

@ -1482,8 +1482,7 @@ int gsi_deregister_device(unsigned long dev_hdl, bool force)
devm_free_irq(gsi_ctx->dev, gsi_ctx->per.irq, gsi_ctx);
gsi_unmap_base();
memset(gsi_ctx, 0, sizeof(*gsi_ctx));
gsi_ctx->per_registered = false;
return GSI_STATUS_SUCCESS;
}
EXPORT_SYMBOL(gsi_deregister_device);
@ -1752,7 +1751,14 @@ static inline uint64_t gsi_read_event_ring_rp_ddr(struct gsi_evt_ring_props* pro
static inline uint64_t gsi_read_event_ring_rp_reg(struct gsi_evt_ring_props* props,
uint8_t id, int ee)
{
return gsi_readl(gsi_ctx->base + GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(id, ee));
uint64_t rp;
rp = gsi_readl(gsi_ctx->base +
GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(id, ee));
rp |= ((uint64_t)gsi_readl(gsi_ctx->base +
GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(id, ee))) << 32;
return rp;
}
int gsi_alloc_evt_ring(struct gsi_evt_ring_props *props, unsigned long dev_hdl,
@ -4051,7 +4057,7 @@ int gsi_poll_n_channel(unsigned long chan_hdl,
/* update rp to see of we have anything new to process */
rp = ctx->evtr->props.gsi_read_event_ring_rp(
&ctx->evtr->props, ctx->evtr->id, ee);
rp |= ctx->ring.rp & 0xFFFFFFFF00000000ULL;
rp |= ctx->evtr->ring.rp & 0xFFFFFFFF00000000ULL;
ctx->evtr->ring.rp = rp;
/* read gsi event ring rp again if last read is empty */
@ -4063,7 +4069,7 @@ int gsi_poll_n_channel(unsigned long chan_hdl,
__iowmb();
rp = ctx->evtr->props.gsi_read_event_ring_rp(
&ctx->evtr->props, ctx->evtr->id, ee);
rp |= ctx->ring.rp & 0xFFFFFFFF00000000ULL;
rp |= ctx->evtr->ring.rp & 0xFFFFFFFF00000000ULL;
ctx->evtr->ring.rp = rp;
if (rp == ctx->evtr->ring.rp_local) {
spin_unlock_irqrestore(

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/debugfs.h>
@ -56,6 +56,16 @@
IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_GSB_ERR_RL(fmt, args...) \
do { \
pr_err_ratelimited_ipa(IPA_GSB_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args); \
IPA_IPC_LOGGING(ipa3_get_ipc_logbuf(), \
IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \
IPA_IPC_LOGGING(ipa3_get_ipc_logbuf_low(), \
IPA_GSB_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_GSB_MAX_MSG_LEN 512
#ifdef CONFIG_DEBUG_FS
@ -1184,7 +1194,7 @@ static int ipa_bridge_tx_dp_internal(u32 hdl, struct sk_buff *skb,
}
if (unlikely(!ipa_gsb_ctx->iface[hdl]->is_resumed)) {
IPA_GSB_ERR("iface %d was suspended\n", hdl);
IPA_GSB_ERR_RL("iface %d was suspended\n", hdl);
return -EFAULT;
}

View file

@ -1,4 +1,6 @@
/* Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -412,6 +414,20 @@ enum ipa_hw_irq_srcs_e {
*/
#define IPA_HW_REG_SAVE_NUM_ACTIVE_PIPES 23
/*
* Total number of channel contexts that need to be saved for q6
*/
#define IPA_HW_REG_SAVE_GSI_NUM_CH_CNTXT_Q6 11
/*
* Total number of event ring contexts that need to be saved for Q6
*/
#define IPA_HW_REG_SAVE_GSI_NUM_EVT_CNTXT_Q6 11
/*
* Macro to set the active flag for all active pipe indexed register
*/
@ -511,7 +527,29 @@ enum ipa_hw_irq_srcs_e {
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_REG_SAVE_HWP_GSI_EE, 3), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.uc[3].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_REG_SAVE_HWP_GSI_EE, 4), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.uc[4].var_name }
(u32 *)&ipa_reg_save.gsi.ch_cntxt.uc[4].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 0), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[0].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 1), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[1].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 2), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[2].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 3), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[3].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 4), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[4].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 5), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[5].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 6), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[6].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 7), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[7].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 8), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[8].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 9), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[9].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 10), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[10].var_name }
#define IPA_REG_SAVE_CFG_ENTRY_GSI_EVT_CNTXT(reg_name, var_name) \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_A7_EE, 0), \
@ -545,7 +583,29 @@ enum ipa_hw_irq_srcs_e {
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_REG_SAVE_HWP_GSI_EE, 2), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.uc[2].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_REG_SAVE_HWP_GSI_EE, 3), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.uc[3].var_name }
(u32 *)&ipa_reg_save.gsi.evt_cntxt.uc[3].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 0), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[0].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 1), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[1].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 2), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[2].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 3), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[3].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 4), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[4].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 5), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[5].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 6), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[6].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 7), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[7].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 8), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[8].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 9), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[9].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 10), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[10].var_name }
/*
* Macro to define a particular register cfg entry for all pipe

View file

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
*/
#if !defined(_IPA_HW_COMMON_EX_H_)
#define _IPA_HW_COMMON_EX_H_
@ -447,6 +449,11 @@ enum ipa_hw_irq_srcs_e {
*/
#define IPA_HW_REG_SAVE_GSI_NUM_CH_CNTXT_UC 2
/*
* Total number of channel contexts that need to be saved for q6
*/
#define IPA_HW_REG_SAVE_GSI_NUM_CH_CNTXT_Q6 11
/*
* Total number of event ring contexts that need to be saved for APPS
*/
@ -456,6 +463,10 @@ enum ipa_hw_irq_srcs_e {
* Total number of event ring contexts that need to be saved for UC
*/
#define IPA_HW_REG_SAVE_GSI_NUM_EVT_CNTXT_UC 1
/*
* Total number of event ring contexts that need to be saved for Q6
*/
#define IPA_HW_REG_SAVE_GSI_NUM_EVT_CNTXT_Q6 11
/*
* Total number of endpoints for which ipa_reg_save.pipes[endp_number]
@ -562,7 +573,31 @@ enum ipa_hw_irq_srcs_e {
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_REG_SAVE_HWP_GSI_EE, 1), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.uc[0].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_REG_SAVE_HWP_GSI_EE, 3), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.uc[1].var_name }
(u32 *)&ipa_reg_save.gsi.ch_cntxt.uc[1].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 0), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[0].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 1), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[1].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 2), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[2].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 3), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[3].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 4), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[4].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 5), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[5].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 6), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[6].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 7), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[7].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 8), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[8].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 9), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[9].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 10), \
(u32 *)&ipa_reg_save.gsi.ch_cntxt.q6[10].var_name }
#define IPA_REG_SAVE_CFG_ENTRY_GSI_EVT_CNTXT(reg_name, var_name) \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_A7_EE, 0), \
@ -604,14 +639,39 @@ enum ipa_hw_irq_srcs_e {
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_A7_EE, 18), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.a7[18].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_REG_SAVE_HWP_GSI_EE, 1), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.uc[0].var_name }
(u32 *)&ipa_reg_save.gsi.evt_cntxt.uc[0].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 0), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[0].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 1), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[1].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 2), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[2].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 3), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[3].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 4), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[4].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 5), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[5].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 6), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[6].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 7), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[7].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 8), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[8].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 9), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[9].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 10), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[10].var_name }, \
{ GEN_2xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE, 11), \
(u32 *)&ipa_reg_save.gsi.evt_cntxt.q6[11].var_name }
/*
* Macro to define a particular register cfg entry for all pipe
* indexed register
*/
#define IPA_REG_SAVE_CFG_ENTRY_PIPE_ENDP(reg_name, var_name) \
({ GEN_1xVECTOR_REG_OFST(reg_name, 0), \
{ GEN_1xVECTOR_REG_OFST(reg_name, 0), \
(u32 *)&ipa_reg_save.ipa.pipes[0].endp.var_name }, \
{ GEN_1xVECTOR_REG_OFST(reg_name, 1), \
(u32 *)&ipa_reg_save.ipa.pipes[1].endp.var_name }, \
@ -672,7 +732,7 @@ enum ipa_hw_irq_srcs_e {
{ GEN_1xVECTOR_REG_OFST(reg_name, 29), \
(u32 *)&ipa_reg_save.ipa.pipes[29].endp.var_name }, \
{ GEN_1xVECTOR_REG_OFST(reg_name, 30), \
(u32 *)&ipa_reg_save.ipa.pipes[30].endp.var_name })
(u32 *)&ipa_reg_save.ipa.pipes[30].endp.var_name }
/*
* Macro to define a particular register cfg entry for the remaining

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "ipa_reg_dump.h"
#include "ipa_access_control.h"
@ -306,6 +307,8 @@ static struct map_src_dst_addr_s ipa_regs_to_save_array[] = {
* because the following registers are not scaler, rather
* they are register arrays...
*/
/* Below are accessable only by VMID0 domain. */
#ifndef CONFIG_IPA3_APPS_REGDUMP
IPA_REG_SAVE_CFG_ENTRY_GEN_EE(IPA_IRQ_STTS_EE_n,
ipa_irq_stts_ee_n),
IPA_REG_SAVE_CFG_ENTRY_GEN_EE(IPA_IRQ_EN_EE_n,
@ -322,6 +325,7 @@ static struct map_src_dst_addr_s ipa_regs_to_save_array[] = {
ipa_suspend_irq_info_ee_n),
IPA_REG_SAVE_CFG_ENTRY_GEN_EE(IPA_SUSPEND_IRQ_EN_EE_n,
ipa_suspend_irq_en_ee_n),
#endif /* CONFIG_IPA3_APPS_REGDUMP */
/* Pipe Endp Registers */
IPA_REG_SAVE_CFG_ENTRY_PIPE_ENDP(IPA_ENDP_INIT_CTRL_n,
@ -370,38 +374,45 @@ static struct map_src_dst_addr_s ipa_regs_to_save_array[] = {
ipa_src_rsrc_grp_01_rsrc_type_n),
IPA_REG_SAVE_CFG_ENTRY_SRC_RSRC_GRP(IPA_SRC_RSRC_GRP_23_RSRC_TYPE_n,
ipa_src_rsrc_grp_23_rsrc_type_n),
#ifdef CONFIG_IPA3_4_5_RGSTR
#if defined(CONFIG_IPA3_REGDUMP_IPA_4_5)
IPA_REG_SAVE_CFG_ENTRY_SRC_RSRC_GRP(IPA_SRC_RSRC_GRP_45_RSRC_TYPE_n,
ipa_src_rsrc_grp_45_rsrc_type_n),
#endif
#endif /* CONFIG_IPA3_REGDUMP_IPA_4_5 */
#endif /* CONFIG_IPA3_4_5_RGSTR */
/* Destination Resource Group Config Registers */
IPA_REG_SAVE_CFG_ENTRY_DST_RSRC_GRP(IPA_DST_RSRC_GRP_01_RSRC_TYPE_n,
ipa_dst_rsrc_grp_01_rsrc_type_n),
IPA_REG_SAVE_CFG_ENTRY_DST_RSRC_GRP(IPA_DST_RSRC_GRP_23_RSRC_TYPE_n,
ipa_dst_rsrc_grp_23_rsrc_type_n),
#ifdef CONFIG_IPA3_4_5_RGSTR
#if defined(CONFIG_IPA3_REGDUMP_IPA_4_5)
IPA_REG_SAVE_CFG_ENTRY_DST_RSRC_GRP(IPA_DST_RSRC_GRP_45_RSRC_TYPE_n,
ipa_dst_rsrc_grp_45_rsrc_type_n),
#endif
#endif /* CONFIG_IPA3_REGDUMP_IPA_4_5 */
#endif /* CONFIG_IPA3_4_5_RGSTR */
/* Source Resource Group Count Registers */
IPA_REG_SAVE_CFG_ENTRY_SRC_RSRC_CNT_GRP(
IPA_SRC_RSRC_GRP_0123_RSRC_TYPE_CNT_n,
ipa_src_rsrc_grp_0123_rsrc_type_cnt_n),
#ifdef CONFIG_IPA3_4_5_RGSTR
#if defined(CONFIG_IPA3_REGDUMP_IPA_4_5)
IPA_REG_SAVE_CFG_ENTRY_SRC_RSRC_CNT_GRP(
IPA_SRC_RSRC_GRP_4567_RSRC_TYPE_CNT_n,
ipa_src_rsrc_grp_4567_rsrc_type_cnt_n),
#endif
#endif /* CONFIG_IPA3_REGDUMP_IPA_4_5 */
#endif /* CONFIG_IPA3_4_5_RGSTR */
/* Destination Resource Group Count Registers */
IPA_REG_SAVE_CFG_ENTRY_DST_RSRC_CNT_GRP(
IPA_DST_RSRC_GRP_0123_RSRC_TYPE_CNT_n,
ipa_dst_rsrc_grp_0123_rsrc_type_cnt_n),
#ifdef CONFIG_IPA3_4_5_RGSTR
#if defined(CONFIG_IPA3_REGDUMP_IPA_4_5)
IPA_REG_SAVE_CFG_ENTRY_DST_RSRC_CNT_GRP(
IPA_DST_RSRC_GRP_4567_RSRC_TYPE_CNT_n,
ipa_dst_rsrc_grp_4567_rsrc_type_cnt_n),
#endif
#endif /* CONFIG_IPA3_REGDUMP_IPA_4_5 */
#endif /* CONFIG_IPA3_4_5_RGSTR */
/*
* =====================================================================
* GSI register definitions begin here...
@ -409,6 +420,9 @@ static struct map_src_dst_addr_s ipa_regs_to_save_array[] = {
*/
/* GSI General Registers */
/* Can access only through VMID_0 domain. */
#ifndef CONFIG_IPA3_APPS_REGDUMP
GEN_SRC_DST_ADDR_MAP(GSI_CFG,
gsi.gen,
gsi_cfg),
@ -419,7 +433,9 @@ static struct map_src_dst_addr_s ipa_regs_to_save_array[] = {
IPA_GSI_TOP_GSI_INST_RAM_n,
ipa_gsi_top_gsi_inst_ram_n),
/* GSI Debug Registers */
/* can access only through VMID_0 domain. */
GEN_SRC_DST_ADDR_MAP(IPA_GSI_TOP_GSI_DEBUG_BUSY_REG,
gsi.debug,
ipa_gsi_top_gsi_debug_busy_reg),
@ -449,6 +465,8 @@ static struct map_src_dst_addr_s ipa_regs_to_save_array[] = {
GSI_DEBUG_QSB_LOG_LAST_MISC_IDn, qsb_log_last_misc),
/* GSI IRAM pointers Registers */
/* can access only through VMID_0 domain */
GEN_SRC_DST_ADDR_MAP(IPA_GSI_TOP_GSI_IRAM_PTR_CH_CMD,
gsi.debug.gsi_iram_ptrs,
ipa_gsi_top_gsi_iram_ptr_ch_cmd),
@ -488,8 +506,10 @@ static struct map_src_dst_addr_s ipa_regs_to_save_array[] = {
GEN_SRC_DST_ADDR_MAP(IPA_GSI_TOP_GSI_IRAM_PTR_INT_MOD_STOPPED,
gsi.debug.gsi_iram_ptrs,
ipa_gsi_top_gsi_iram_ptr_int_mod_stopped),
/* GSI SHRAM pointers Registers */
/* can access only through VMID_0 domain */
GEN_SRC_DST_ADDR_MAP(IPA_GSI_TOP_GSI_SHRAM_PTR_CH_CNTXT_BASE_ADDR,
gsi.debug.gsi_shram_ptrs,
ipa_gsi_top_gsi_shram_ptr_ch_cntxt_base_addr),
@ -508,7 +528,6 @@ static struct map_src_dst_addr_s ipa_regs_to_save_array[] = {
GEN_SRC_DST_ADDR_MAP(IPA_GSI_TOP_GSI_SHRAM_PTR_FUNC_STACK_BASE_ADDR,
gsi.debug.gsi_shram_ptrs,
ipa_gsi_top_gsi_shram_ptr_func_stack_base_addr),
/*
* NOTE: That GEN_SRC_DST_ADDR_MAP() not used below. This is
* because the following registers are not scaler, rather
@ -516,8 +535,12 @@ static struct map_src_dst_addr_s ipa_regs_to_save_array[] = {
*/
/* GSI General EE Registers */
/* can access only through VMID_0 domain */
IPA_REG_SAVE_CFG_ENTRY_GSI_GENERAL_EE(GSI_MANAGER_EE_QOS_n,
gsi_manager_ee_qos_n),
#endif /* CONFIG_IPA3_APPS_REGDUMP */
IPA_REG_SAVE_CFG_ENTRY_GSI_GENERAL_EE(EE_n_GSI_STATUS,
ee_n_gsi_status),
IPA_REG_SAVE_CFG_ENTRY_GSI_GENERAL_EE(EE_n_CNTXT_TYPE_IRQ,
@ -659,12 +682,17 @@ static struct map_src_dst_addr_s ipa_regs_to_save_array[] = {
ipa_endp_init_rsrc_grp_n),
IPA_REG_SAVE_CFG_ENTRY_PIPE_ENDP_EXTRA(IPA_ENDP_INIT_SEQ_n,
ipa_endp_init_seq_n),
/* can access only through VMID_0 domain */
#ifndef CONFIG_IPA3_APPS_REGDUMP
IPA_REG_SAVE_CFG_ENTRY_PIPE_ENDP_EXTRA(IPA_ENDP_GSI_CFG_TLV_n,
ipa_endp_gsi_cfg_tlv_n),
IPA_REG_SAVE_CFG_ENTRY_PIPE_ENDP_EXTRA(IPA_ENDP_GSI_CFG_AOS_n,
ipa_endp_gsi_cfg_aos_n),
IPA_REG_SAVE_CFG_ENTRY_PIPE_ENDP_EXTRA(IPA_ENDP_GSI_CFG1_n,
ipa_endp_gsi_cfg1_n),
#endif /* CONFIG_IPA3_APPS_REGDUMP */
IPA_REG_SAVE_CFG_ENTRY_PIPE_ENDP_EXTRA
(IPA_ENDP_FILTER_ROUTER_HSH_CFG_n,
ipa_endp_filter_router_hsh_cfg_n),
@ -707,7 +735,9 @@ static struct map_src_dst_addr_s ipa_uc_regs_to_save_array[] = {
};
static void ipa_hal_save_regs_save_ipa_testbus(void);
#ifndef CONFIG_IPA3_APPS_REGDUMP
static void ipa_reg_save_gsi_fifo_status(void);
#endif /* CONFIG_IPA3_APPS_REGDUMP */
static void ipa_reg_save_rsrc_cnts(void);
static void ipa_hal_save_regs_ipa_cmdq(void);
static void ipa_hal_save_regs_rsrc_db(void);
@ -837,9 +867,10 @@ void ipa_save_registers(void)
num_regs += (CONFIG_IPA3_REGDUMP_NUM_EXTRA_ENDP_REGS *
IPA_REG_SAVE_NUM_EXTRA_ENDP_REGS);
#ifndef CONFIG_IPA3_APPS_REGDUMP
/* Saving GSI FIFO Status registers */
ipa_reg_save_gsi_fifo_status();
#endif /* CONFIG_IPA3_APPS_REGDUMP */
/*
* On targets that support SSR, we generally want to disable
* the following reg save functionality as it may cause stalls
@ -868,6 +899,7 @@ void ipa_save_registers(void)
}
/* GSI test bus */
#ifndef CONFIG_IPA3_APPS_REGDUMP
for (i = 0;
i < ARRAY_SIZE(ipa_reg_save_gsi_ch_test_bus_selector_array);
i++) {
@ -883,6 +915,7 @@ void ipa_save_registers(void)
i].gsi_testbus_reg =
(u32) IPA_READ_SCALER_REG(GSI_TEST_BUS_REG);
}
#endif /* CONFIG_IPA3_APPS_REGDUMP */
ipa_reg_save_rsrc_cnts();
@ -1039,6 +1072,7 @@ void ipa_save_registers(void)
*
* @return
*/
#ifndef CONFIG_IPA3_APPS_REGDUMP
static void ipa_reg_save_gsi_fifo_status(void)
{
union ipa_hwio_def_ipa_gsi_fifo_status_ctrl_u gsi_fifo_status_ctrl;
@ -1061,7 +1095,7 @@ static void ipa_reg_save_gsi_fifo_status(void)
IPA_READ_SCALER_REG(IPA_GSI_AOS_FIFO_STATUS);
}
}
#endif /* CONFIG_IPA3_APPS_REGDUMP */
/*
* FUNCTION: ipa_reg_save_rsrc_cnts
*
@ -1490,7 +1524,7 @@ int ipa_reg_save_init(u32 value)
if (ipa3_ctx->do_testbus_collection_on_crash) {
memset(ipa_testbus_mem, value, sizeof(ipa_testbus_mem));
ipa_reg_save.ipa.testbus =
(struct ipa_reg_save_ipa_testbus_s *) ipa_testbus_mem;
(struct ipa_reg_save_ipa_testbus_s *) ipa_testbus_mem;
}
/* setup access for register collection/dump on crash */

View file

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#if !defined(_IPA_REG_DUMP_H_)
#define _IPA_REG_DUMP_H_
@ -242,18 +243,33 @@ struct map_src_dst_addr_s {
#define IPA_REG_SAVE_GSI_VER(reg_name, var_name) \
{ GEN_1xVECTOR_REG_OFST(reg_name, 0), \
(u32 *)&ipa_reg_save.gsi.gen.var_name }
/*
* Macro to define a particular register cfg entry for all 3 EE
* indexed register
*/
#ifdef CONFIG_IPA3_APPS_REGDUMP
#define IPA_REG_SAVE_CFG_ENTRY_GEN_EE(reg_name, var_name) \
{ GEN_1xVECTOR_REG_OFST(reg_name, IPA_HW_A7_EE), \
(u32 *)&ipa_reg_save.ipa.gen_ee[IPA_HW_A7_EE].var_name }
#else
#define IPA_REG_SAVE_CFG_ENTRY_GEN_EE(reg_name, var_name) \
{ GEN_1xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE), \
(u32 *)&ipa_reg_save.ipa.gen_ee[IPA_HW_Q6_EE].var_name }, \
{ GEN_1xVECTOR_REG_OFST(reg_name, IPA_HW_A7_EE), \
(u32 *)&ipa_reg_save.ipa.gen_ee[IPA_HW_A7_EE].var_name }, \
{ GEN_1xVECTOR_REG_OFST(reg_name, IPA_HW_Q6_EE), \
(u32 *)&ipa_reg_save.ipa.gen_ee[IPA_HW_Q6_EE].var_name }, \
{ GEN_1xVECTOR_REG_OFST(reg_name, IPA_HW_HWP_EE), \
(u32 *)&ipa_reg_save.ipa.gen_ee[IPA_HW_HWP_EE].var_name }
#endif /* CONFIG_IPA3_APPS_REGDUMP */
#define IPA_REG_SAVE_CFG_ENTRY_GSI_FIFO(reg_name, var_name, index) \
{ GEN_SCALER_REG_OFST(reg_name), \
(u32 *)&ipa_reg_save.ipa.gsi_fifo_status[index].var_name }
@ -1115,6 +1131,9 @@ struct ipa_reg_save_gsi_ch_cntxt_s {
a7[IPA_HW_REG_SAVE_GSI_NUM_CH_CNTXT_A7];
struct ipa_reg_save_gsi_ch_cntxt_per_ep_s
uc[IPA_HW_REG_SAVE_GSI_NUM_CH_CNTXT_UC];
struct ipa_reg_save_gsi_ch_cntxt_per_ep_s
q6[IPA_HW_REG_SAVE_GSI_NUM_CH_CNTXT_Q6];
};
/* GSI Event Context register save top level data struct */
@ -1123,6 +1142,9 @@ struct ipa_reg_save_gsi_evt_cntxt_s {
a7[IPA_HW_REG_SAVE_GSI_NUM_EVT_CNTXT_A7];
struct ipa_reg_save_gsi_evt_cntxt_per_ep_s
uc[IPA_HW_REG_SAVE_GSI_NUM_EVT_CNTXT_UC];
struct ipa_reg_save_gsi_evt_cntxt_per_ep_s
q6[IPA_HW_REG_SAVE_GSI_NUM_EVT_CNTXT_Q6];
};
/* Top level IPA register save data struct */

View file

@ -41,6 +41,7 @@
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/suspend.h>
#ifdef CONFIG_ARM64
@ -51,7 +52,7 @@
#endif
#define DRV_NAME "ipa"
#define DELAY_BEFORE_FW_LOAD 500
#define IPA_SUBSYSTEM_NAME "ipa_fws"
#define IPA_UC_SUBSYSTEM_NAME "ipa_uc"
@ -124,8 +125,14 @@ static void ipa_gsi_notify_cb(struct gsi_per_notify *notify);
static int ipa3_attach_to_smmu(void);
static int ipa3_alloc_pkt_init(void);
#ifdef CONFIG_DEEPSLEEP
static void ipa3_deepsleep_resume(void);
static void ipa3_deepsleep_suspend(void);
#endif
static void ipa3_load_ipa_fw(struct work_struct *work);
static DECLARE_WORK(ipa3_fw_loading_work, ipa3_load_ipa_fw);
static DECLARE_DELAYED_WORK(ipa3_fw_load_failure_handle, ipa3_load_ipa_fw);
static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work);
static DECLARE_DELAYED_WORK(ipa_dec_clients_disable_clks_on_wq_work,
@ -437,6 +444,38 @@ int ipa_smmu_free_sgt(struct sg_table **out_sgt_ptr)
}
EXPORT_SYMBOL(ipa_smmu_free_sgt);
/**
* ipa_pm_notify() - PM notify to listen suspend events
*
* This callback will be invoked by the pm framework to suspend
* operation is invoked.
*
* Returns NOTIFY_DONE to pm framework completed operation.
*/
static int ipa_pm_notify(struct notifier_block *b, unsigned long event, void *p)
{
IPAERR("Entry\n");
switch (event) {
case PM_POST_SUSPEND:
#ifdef CONFIG_DEEPSLEEP
if (mem_sleep_current == PM_SUSPEND_MEM && ipa3_ctx->deepsleep) {
IPADBG("Enter deepsleep resume\n");
ipa3_deepsleep_resume();
IPADBG("Exit deepsleep resume\n");
}
#endif
break;
}
IPAERR("Exit\n");
return NOTIFY_DONE;
}
static struct notifier_block ipa_pm_notifier = {
.notifier_call = ipa_pm_notify,
};
static const struct dev_pm_ops ipa_pm_ops = {
.suspend_late = ipa3_ap_suspend,
.resume_early = ipa3_ap_resume,
@ -3566,16 +3605,18 @@ static void ipa3_q6_avoid_holb(void)
* setting HOLB on Q6 pipes, and from APPS perspective
* they are not valid, therefore, the above function
* will fail.
* Also don't reset the HOLB timer to 0 for Q6 pipes.
*/
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_HOL_BLOCK_TIMER_n,
ep_idx, &ep_holb);
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_HOL_BLOCK_EN_n,
ep_idx, &ep_holb);
/* IPA4.5 issue requires HOLB_EN to be written twice */
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5)
/* For targets > IPA_4.0 issue requires HOLB_EN to
* be written twice.
*/
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_HOL_BLOCK_EN_n,
ep_idx, &ep_holb);
@ -5060,6 +5101,7 @@ static void ipa3_teardown_apps_pipes(void)
__ipa3_del_rt_rule(ipa3_ctx->dflt_v4_rt_rule_hdl);
__ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl, false);
ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_cmd);
ipa3_dealloc_common_event_ring();
}
#ifdef CONFIG_COMPAT
@ -6314,6 +6356,12 @@ static inline void ipa3_enable_napi_lan_rx(void)
napi_enable(&ipa3_ctx->napi_lan_rx);
}
static inline void ipa3_disable_napi_lan_rx(void)
{
if (ipa3_ctx->lan_rx_napi_enable)
napi_disable(&ipa3_ctx->napi_lan_rx);
}
static inline void ipa3_register_to_fmwk(void)
{
struct ipa_core_data data;
@ -6688,6 +6736,11 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p,
IPADBG("register to fmwk\n");
ipa3_register_to_fmwk();
}
#ifdef CONFIG_DEEPSLEEP
if (!ipa3_is_ready())
ipa_fmwk_deepsleep_exit_ipa();
#endif
complete_all(&ipa3_ctx->init_completion_obj);
ipa_ut_module_init();
@ -6790,13 +6843,12 @@ static int ipa3_manual_load_ipa_fws(void)
static int ipa3_pil_load_ipa_fws(const char *sub_sys)
{
void *subsystem_get_retval = NULL;
IPADBG("PIL FW loading process initiated sub_sys=%s\n",
sub_sys);
subsystem_get_retval = subsystem_get(sub_sys);
if (IS_ERR_OR_NULL(subsystem_get_retval)) {
ipa3_ctx->subsystem_get_retval = subsystem_get(sub_sys);
if (IS_ERR_OR_NULL(ipa3_ctx->subsystem_get_retval)) {
IPAERR("Unable to PIL load FW for sub_sys=%s\n", sub_sys);
return -EINVAL;
}
@ -6805,6 +6857,20 @@ static int ipa3_pil_load_ipa_fws(const char *sub_sys)
return 0;
}
#ifdef CONFIG_DEEPSLEEP
static int ipa3_pil_unload_ipa_fws(void)
{
IPADBG("PIL FW unloading process initiated sub_sys\n");
if (ipa3_ctx->subsystem_get_retval)
subsystem_put(ipa3_ctx->subsystem_get_retval);
IPADBG("PIL FW unloading process is complete sub_sys\n");
return 0;
}
#endif
static void ipa3_load_ipa_fw(struct work_struct *work)
{
int result;
@ -6812,11 +6878,14 @@ static void ipa3_load_ipa_fw(struct work_struct *work)
IPADBG("Entry\n");
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
result = ipa3_attach_to_smmu();
if (result) {
IPAERR("IPA attach to smmu failed %d\n", result);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq,
&ipa3_fw_load_failure_handle,
msecs_to_jiffies(DELAY_BEFORE_FW_LOAD));
return;
}
@ -6836,13 +6905,18 @@ static void ipa3_load_ipa_fw(struct work_struct *work)
result = ipa3_manual_load_ipa_fws();
}
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
if (result) {
IPAERR("IPA FW loading process has failed result=%d\n",
result);
ipa3_ctx->ipa_pil_load++;
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
IPADBG("IPA firmware loading deffered to a work queue\n");
queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq,
&ipa3_fw_load_failure_handle,
msecs_to_jiffies(DELAY_BEFORE_FW_LOAD));
return;
}
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
mutex_lock(&ipa3_ctx->fw_load_data.lock);
ipa3_ctx->fw_load_data.state = IPA_FW_LOAD_STATE_LOADED;
mutex_unlock(&ipa3_ctx->fw_load_data.lock);
@ -6902,7 +6976,7 @@ static void ipa_fw_load_sm_handle_event(enum ipa_fw_load_event ev)
if (ipa3_ctx->fw_load_data.state == IPA_FW_LOAD_STATE_INIT) {
ipa3_ctx->fw_load_data.state =
IPA_FW_LOAD_STATE_SMMU_DONE;
goto out;
goto sched_fw_load;
}
if (ipa3_ctx->fw_load_data.state ==
IPA_FW_LOAD_STATE_FWFILE_READY) {
@ -7873,8 +7947,10 @@ fail_mem_ctrl:
kfree(ipa3_ctx->ipa_tz_unlock_reg);
ipa3_ctx->ipa_tz_unlock_reg = NULL;
fail_tz_unlock_reg:
if (ipa3_ctx->logbuf)
if (ipa3_ctx->logbuf) {
ipc_log_context_destroy(ipa3_ctx->logbuf);
ipa3_ctx->logbuf = NULL;
}
fail_uc_file_alloc:
kfree(ipa3_ctx->gsi_fw_file_name);
ipa3_ctx->gsi_fw_file_name = NULL;
@ -8807,6 +8883,7 @@ static int ipa_smmu_wlan_cb_probe(struct device *dev)
}
}
cb->done = true;
return 0;
}
@ -8886,10 +8963,35 @@ static int ipa_smmu_uc_cb_probe(struct device *dev)
ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] = (bypass != 0);
ipa3_ctx->uc_pdev = dev;
cb->done = true;
return 0;
}
static void ipa3_ap_iommu_unmap(struct ipa_smmu_cb_ctx *cb, const u32 *add_map, u32 add_map_size) {
int i, res;
/* iterate of each entry of the additional mapping array */
for (i = 0; i < add_map_size / sizeof(u32); i += 3) {
u32 iova = be32_to_cpu(add_map[i]);
u32 pa = be32_to_cpu(add_map[i + 1]);
u32 size = be32_to_cpu(add_map[i + 2]);
unsigned long iova_p;
phys_addr_t pa_p;
u32 size_p;
IPA_SMMU_ROUND_TO_PAGE(iova, pa, size,
iova_p, pa_p, size_p);
IPADBG_LOW("unmapping 0x%lx to 0x%pa size %d\n",
iova_p, &pa_p, size_p);
res = iommu_unmap(cb->iommu_domain,iova_p, size_p);
if(res != size_p) {
pr_err("iommu unmap failed for AP cb\n");
ipa_assert();
}
}
}
static int ipa_smmu_ap_cb_probe(struct device *dev)
{
struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
@ -9024,6 +9126,8 @@ static int ipa_smmu_ap_cb_probe(struct device *dev)
if (ret < 0 && ret != -EEXIST) {
IPAERR("unable to allocate smem MODEM entry\n");
cb->valid = false;
if(add_map)
ipa3_ap_iommu_unmap(cb, add_map, add_map_size);
return -EFAULT;
}
smem_addr = qcom_smem_get(SMEM_MODEM,
@ -9032,6 +9136,8 @@ static int ipa_smmu_ap_cb_probe(struct device *dev)
if (IS_ERR(smem_addr)) {
IPAERR("unable to acquire smem MODEM entry\n");
cb->valid = false;
if(add_map)
ipa3_ap_iommu_unmap(cb, add_map, add_map_size);
return -EFAULT;
}
if (smem_size != ipa_smem_size)
@ -9052,6 +9158,7 @@ static int ipa_smmu_ap_cb_probe(struct device *dev)
smmu_info.present[IPA_SMMU_CB_AP] = true;
cb->done = true;
ipa3_ctx->pdev = dev;
cb->next_addr = cb->va_end;
@ -9104,18 +9211,26 @@ static int ipa_smmu_11ad_cb_probe(struct device *dev)
IPADBG("11AD using shared CB\n");
cb->shared = true;
}
cb->done = true;
return 0;
}
static int ipa_smmu_cb_probe(struct device *dev, enum ipa_smmu_cb_type cb_type)
{
struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(cb_type);
if((cb != NULL) && (cb->done == true)) {
IPADBG("SMMU CB type %d already initialized\n", cb_type);
return 0;
}
switch (cb_type) {
case IPA_SMMU_CB_AP:
ipa3_ctx->pdev = &ipa3_ctx->master_pdev->dev;
return ipa_smmu_ap_cb_probe(dev);
case IPA_SMMU_CB_WLAN:
return ipa_smmu_wlan_cb_probe(dev);
case IPA_SMMU_CB_UC:
ipa3_ctx->uc_pdev = &ipa3_ctx->master_pdev->dev;
return ipa_smmu_uc_cb_probe(dev);
case IPA_SMMU_CB_11AD:
return ipa_smmu_11ad_cb_probe(dev);
@ -9130,18 +9245,19 @@ static int ipa3_attach_to_smmu(void)
struct ipa_smmu_cb_ctx *cb;
int i, result;
ipa3_ctx->pdev = &ipa3_ctx->master_pdev->dev;
ipa3_ctx->uc_pdev = &ipa3_ctx->master_pdev->dev;
if (smmu_info.arm_smmu) {
IPADBG("smmu is enabled\n");
for (i = 0; i < IPA_SMMU_CB_MAX; i++) {
cb = ipa3_get_smmu_ctx(i);
result = ipa_smmu_cb_probe(cb->dev, i);
if (result)
if (result) {
IPAERR("probe failed for cb %d\n", i);
return result;
}
}
} else {
ipa3_ctx->pdev = &ipa3_ctx->master_pdev->dev;
ipa3_ctx->uc_pdev = &ipa3_ctx->master_pdev->dev;
IPADBG("smmu is disabled\n");
}
return 0;
@ -9424,7 +9540,17 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p)
return -EOPNOTSUPP;
}
}
/* Below update of pre init for non smmu device, As
* existing flow initialzies only for smmu
* enabled node.*/
result = ipa3_pre_init(&ipa3_res, pdev_p);
if (result) {
IPAERR("ipa3_init failed\n");
return result;
}
ipa_fw_load_sm_handle_event(IPA_FW_LOAD_EVNT_SMMU_DONE);
goto skip_repeat_pre_init;
}
/* Proceed to real initialization */
@ -9434,6 +9560,7 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p)
return result;
}
skip_repeat_pre_init:
result = of_platform_populate(pdev_p->dev.of_node,
ipa_plat_drv_match, NULL, &pdev_p->dev);
if (result) {
@ -9462,7 +9589,8 @@ int ipa3_ap_suspend(struct device *dev)
int i;
IPADBG("Enter...\n");
if (!of_device_is_compatible(dev->of_node,"qcom,ipa"))
return 0;
/* In case there is a tx/rx handler in polling mode fail to suspend */
for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
if (ipa3_ctx->ep[i].sys &&
@ -9473,6 +9601,13 @@ int ipa3_ap_suspend(struct device *dev)
}
}
#ifdef CONFIG_DEEPSLEEP
if (mem_sleep_current == PM_SUSPEND_MEM) {
IPADBG("Enter deepsleep suspend\n");
ipa3_deepsleep_suspend();
IPADBG("Exit deepsleep suspend\n");
}
#endif
ipa_pm_deactivate_all_deferred();
IPADBG("Exit\n");
@ -9505,6 +9640,59 @@ bool ipa3_get_lan_rx_napi(void)
return ipa3_ctx->lan_rx_napi_enable;
}
#ifdef CONFIG_DEEPSLEEP
static void ipa3_deepsleep_suspend(void)
{
IPADBG("Entry\n");
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
/* To allow default routing table delection using this flag */
ipa3_ctx->deepsleep = true;
/*Disabling the LAN NAPI*/
ipa3_disable_napi_lan_rx();
/*NOt allow uC related operations until uC load again*/
ipa3_ctx->uc_ctx.uc_loaded = false;
/*Disconnecting LAN PROD/LAN CONS/CMD PROD apps pipes*/
ipa3_teardown_apps_pipes();
/*Deregistering the GSI driver*/
gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false);
/*Destroying filter table ids*/
ipa3_destroy_flt_tbl_idrs();
/*Disabling IPA interrupt*/
ipa3_remove_interrupt_handler(IPA_TX_SUSPEND_IRQ);
ipa3_interrupts_destroy(ipa3_res.ipa_irq, &ipa3_ctx->master_pdev->dev);
ipa3_uc_interface_destroy();
/*Destroy the NAT device*/
ipa3_nat_ipv6ct_destroy_devices();
/*Freeing memory allocated for coalesing and dma task*/
ipa3_free_coal_close_frame();
ipa3_free_dma_task_for_gsi();
/*Destroying ipa hal module*/
ipahal_destroy();
ipa3_ctx->ipa_initialization_complete = false;
ipa3_debugfs_remove();
/*Unloading IPA FW to allow FW load in resume*/
ipa3_pil_unload_ipa_fws();
/*Calling framework API to reset IPA ready flag to false*/
ipa_fmwk_deepsleep_entry_ipa();
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
IPADBG("Exit\n");
}
static void ipa3_deepsleep_resume(void)
{
IPADBG("Entry\n");
/*After deeplseep exit we shouldn't allow delete the default routing table*/
ipa3_ctx->deepsleep = false;
/*Scheduling WQ to load IPA FW*/
queue_work(ipa3_ctx->transport_power_mgmt_wq,
&ipa3_fw_loading_work);
IPADBG("Exit\n");
}
#endif
static void ipa_gsi_notify_cb(struct gsi_per_notify *notify)
{
/*
@ -9934,6 +10122,8 @@ static int __init ipa_module_init(void)
/* Register as a PCI device driver */
return pci_register_driver(&ipa_pci_driver);
}
register_pm_notifier(&ipa_pm_notifier);
/* Register as a platform device driver */
return platform_driver_register(&ipa_plat_drv);
}
@ -9944,6 +10134,7 @@ static void __exit ipa_module_exit(void)
if (running_emulation)
pci_unregister_driver(&ipa_pci_driver);
platform_driver_unregister(&ipa_plat_drv);
unregister_pm_notifier(&ipa_pm_notifier);
kfree(ipa3_ctx);
ipa3_ctx = NULL;
}

View file

@ -67,6 +67,7 @@ int ipa3_enable_data_path(u32 clnt_hdl)
holb_cfg.en = IPA_HOLB_TMR_EN;
} else if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_11 &&
(ep->client == IPA_CLIENT_WLAN1_CONS ||
ep->client == IPA_CLIENT_WLAN2_CONS ||
ep->client == IPA_CLIENT_USB_CONS)) {
holb_cfg.en = IPA_HOLB_TMR_EN;
holb_cfg.tmr_val = IPA_HOLB_TMR_VAL_4_5;
@ -1497,8 +1498,10 @@ int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset, u32 tmr_val,
IPA_ENDP_INIT_HOL_BLOCK_EN_n,
pipe_idx, &ep_holb);
/* IPA4.5 issue requires HOLB_EN to be written twice */
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5)
/* For targets > IPA_4.0 issue requires HOLB_EN to be
* written twice.
*/
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
ipahal_write_reg_n_fields(
IPA_ENDP_INIT_HOL_BLOCK_EN_n,
pipe_idx, &ep_holb);

View file

@ -1357,7 +1357,8 @@ static ssize_t ipa3_read_stats(struct file *file, char __user *ubuf,
"lan_repl_rx_empty=%u\n"
"flow_enable=%u\n"
"flow_disable=%u\n"
"rx_page_drop_cnt=%u\n",
"rx_page_drop_cnt=%u\n"
"lower_order=%u\n",
ipa3_ctx->stats.tx_sw_pkts,
ipa3_ctx->stats.tx_hw_pkts,
ipa3_ctx->stats.tx_non_linear,
@ -1374,7 +1375,8 @@ static ssize_t ipa3_read_stats(struct file *file, char __user *ubuf,
ipa3_ctx->stats.lan_repl_rx_empty,
ipa3_ctx->stats.flow_enable,
ipa3_ctx->stats.flow_disable,
ipa3_ctx->stats.rx_page_drop_cnt
ipa3_ctx->stats.rx_page_drop_cnt,
ipa3_ctx->stats.lower_order
);
cnt += nbytes;

View file

@ -345,20 +345,22 @@ static void ipa3_send_nop_desc(struct work_struct *work)
return;
}
list_add_tail(&tx_pkt->link, &sys->head_desc_list);
sys->len++;
sys->nop_pending = false;
memset(&nop_xfer, 0, sizeof(nop_xfer));
nop_xfer.type = GSI_XFER_ELEM_NOP;
nop_xfer.flags = GSI_XFER_FLAG_EOT;
nop_xfer.xfer_user_data = tx_pkt;
if (gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1, &nop_xfer, true)) {
list_del(&tx_pkt->link);
kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
spin_unlock_bh(&sys->spinlock);
IPAERR("gsi_queue_xfer for ch:%lu failed\n",
sys->ep->gsi_chan_hdl);
queue_work(sys->wq, &sys->work);
return;
}
sys->len++;
sys->nop_pending = false;
spin_unlock_bh(&sys->spinlock);
/* make sure TAG process is sent before clocks are gated */
@ -2040,6 +2042,27 @@ fail_kmem_cache_alloc:
}
}
static struct page *ipa3_alloc_page(
gfp_t flag, u32 *page_order, bool try_lower)
{
struct page *page = NULL;
u32 p_order = *page_order;
page = __dev_alloc_pages(flag, p_order);
/* We will only try 1 page order lower. */
if (unlikely(!page)) {
if (try_lower && p_order > 0) {
p_order = p_order - 1;
page = __dev_alloc_pages(flag, p_order);
if (likely(page))
ipa3_ctx->stats.lower_order++;
}
}
*page_order = p_order;
return page;
}
static struct ipa3_rx_pkt_wrapper *ipa3_alloc_rx_pkt_page(
gfp_t flag, bool is_tmp_alloc)
{
@ -2050,12 +2073,18 @@ static struct ipa3_rx_pkt_wrapper *ipa3_alloc_rx_pkt_page(
flag);
if (unlikely(!rx_pkt))
return NULL;
rx_pkt->len = PAGE_SIZE << IPA_WAN_PAGE_ORDER;
rx_pkt->page_data.page = __dev_alloc_pages(flag,
IPA_WAN_PAGE_ORDER);
rx_pkt->page_data.page_order = IPA_WAN_PAGE_ORDER;
/* Try a lower order page for order 3 pages in case allocation fails. */
rx_pkt->page_data.page = ipa3_alloc_page(flag,
&rx_pkt->page_data.page_order,
(is_tmp_alloc && rx_pkt->page_data.page_order == 3));
if (unlikely(!rx_pkt->page_data.page))
goto fail_page_alloc;
rx_pkt->len = PAGE_SIZE << rx_pkt->page_data.page_order;
rx_pkt->page_data.dma_addr = dma_map_page(ipa3_ctx->pdev,
rx_pkt->page_data.page, 0,
rx_pkt->len, DMA_FROM_DEVICE);
@ -2073,7 +2102,7 @@ static struct ipa3_rx_pkt_wrapper *ipa3_alloc_rx_pkt_page(
return rx_pkt;
fail_dma_mapping:
__free_pages(rx_pkt->page_data.page, IPA_WAN_PAGE_ORDER);
__free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order);
fail_page_alloc:
kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt);
return NULL;
@ -2567,7 +2596,7 @@ static void ipa3_replenish_rx_cache_recycle(struct ipa3_sys_context *sys)
spin_lock_bh(&sys->spinlock);
rx_pkt = list_first_entry(&sys->rcycl_list,
struct ipa3_rx_pkt_wrapper, link);
list_del(&rx_pkt->link);
list_del_init(&rx_pkt->link);
spin_unlock_bh(&sys->spinlock);
ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev,
@ -2608,8 +2637,8 @@ static void ipa3_replenish_rx_cache_recycle(struct ipa3_sys_context *sys)
goto done;
fail_dma_mapping:
spin_lock_bh(&sys->spinlock);
ipa3_skb_recycle(rx_pkt->data.skb);
list_add_tail(&rx_pkt->link, &sys->rcycl_list);
INIT_LIST_HEAD(&rx_pkt->link);
spin_unlock_bh(&sys->spinlock);
fail_kmem_cache_alloc:
if (rx_len_cached == 0) {
@ -2767,8 +2796,7 @@ static void free_rx_page(void *chan_user_data, void *xfer_user_data)
}
dma_unmap_page(ipa3_ctx->pdev, rx_pkt->page_data.dma_addr,
rx_pkt->len, DMA_FROM_DEVICE);
__free_pages(rx_pkt->page_data.page,
IPA_WAN_PAGE_ORDER);
__free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order);
kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt);
}
@ -2819,8 +2847,7 @@ static void ipa3_cleanup_rx(struct ipa3_sys_context *sys)
rx_pkt->page_data.dma_addr,
rx_pkt->len,
DMA_FROM_DEVICE);
__free_pages(rx_pkt->page_data.page,
IPA_WAN_PAGE_ORDER);
__free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order);
}
kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache,
rx_pkt);
@ -2840,7 +2867,7 @@ static void ipa3_cleanup_rx(struct ipa3_sys_context *sys)
rx_pkt->len,
DMA_FROM_DEVICE);
__free_pages(rx_pkt->page_data.page,
IPA_WAN_PAGE_ORDER);
rx_pkt->page_data.page_order);
kmem_cache_free(
ipa3_ctx->rx_pkt_wrapper_cache,
rx_pkt);
@ -3640,8 +3667,7 @@ static struct sk_buff *handle_page_completion(struct gsi_chan_xfer_notify
} else {
dma_unmap_page(ipa3_ctx->pdev, rx_page.dma_addr,
rx_pkt->len, DMA_FROM_DEVICE);
__free_pages(rx_pkt->page_data.page,
IPA_WAN_PAGE_ORDER);
__free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order);
}
rx_pkt->sys->free_rx_wrapper(rx_pkt);
IPA_STATS_INC_CNT(ipa3_ctx->stats.rx_page_drop_cnt);
@ -3658,17 +3684,21 @@ static struct sk_buff *handle_page_completion(struct gsi_chan_xfer_notify
sys->ep->client == IPA_CLIENT_APPS_LAN_CONS) {
rx_skb = alloc_skb(0, GFP_ATOMIC);
if (unlikely(!rx_skb)) {
IPAERR("skb alloc failure\n");
list_del(&rx_pkt->link);
if (!rx_page.is_tmp_alloc) {
init_page_count(rx_page.page);
} else {
dma_unmap_page(ipa3_ctx->pdev, rx_page.dma_addr,
rx_pkt->len, DMA_FROM_DEVICE);
__free_pages(rx_pkt->page_data.page,
IPA_WAN_PAGE_ORDER);
IPAERR("skb alloc failure, free all pending pages\n");
list_for_each_entry_safe(rx_pkt, tmp, head, link) {
rx_page = rx_pkt->page_data;
size = rx_pkt->data_len;
list_del_init(&rx_pkt->link);
if (!rx_page.is_tmp_alloc) {
init_page_count(rx_page.page);
} else {
dma_unmap_page(ipa3_ctx->pdev, rx_page.dma_addr,
rx_pkt->len, DMA_FROM_DEVICE);
__free_pages(rx_pkt->page_data.page,
rx_pkt->page_data.page_order);
}
rx_pkt->sys->free_rx_wrapper(rx_pkt);
}
rx_pkt->sys->free_rx_wrapper(rx_pkt);
IPA_STATS_INC_CNT(ipa3_ctx->stats.rx_page_drop_cnt);
return NULL;
}
@ -3690,7 +3720,7 @@ static struct sk_buff *handle_page_completion(struct gsi_chan_xfer_notify
skb_shinfo(rx_skb)->nr_frags,
rx_page.page, 0,
size,
PAGE_SIZE << IPA_WAN_PAGE_ORDER);
PAGE_SIZE << rx_page.page_order);
}
} else {
return NULL;
@ -4735,6 +4765,13 @@ static void ipa_dma_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify)
}
}
void ipa3_dealloc_common_event_ring(void)
{
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
gsi_dealloc_evt_ring(ipa3_ctx->gsi_evt_comm_hdl);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
}
int ipa3_alloc_common_event_ring(void)
{
struct gsi_evt_ring_props gsi_evt_ring_props;

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
*/
#include "ipa_i.h"
@ -90,6 +90,12 @@ static int ipa3_hdr_proc_ctx_to_hw_format(struct ipa_mem_buffer *mem,
0 : 1;
}
}
/* Check the pointer and header length to avoid dangerous overflow in HW */
if (unlikely(!entry->hdr || !entry->hdr->offset_entry ||
!entry->offset_entry ||
entry->hdr->hdr_len == 0 ||
entry->hdr->hdr_len > ipa_hdr_bin_sz[IPA_HDR_BIN_MAX - 1]))
return -EINVAL;
ret = ipahal_cp_proc_ctx_to_hw_buff(entry->type, mem->base,
entry->offset_entry->offset,
@ -184,13 +190,13 @@ int __ipa_commit_hdr_v3_0(void)
if (ipa3_generate_hdr_hw_tbl(&hdr_mem)) {
IPAERR("fail to generate HDR HW TBL\n");
goto end;
goto failure_hdr;
}
if (ipa3_generate_hdr_proc_ctx_hw_tbl(hdr_mem.phys_base, &ctx_mem,
&aligned_ctx_mem)) {
IPAERR("fail to generate HDR PROC CTX HW TBL\n");
goto end;
goto failure_hdr_proc;
}
/* IC to close the coal frame before HPS Clear if coal is enabled */
@ -316,6 +322,7 @@ int __ipa_commit_hdr_v3_0(void)
else
rc = 0;
end:
if (ipa3_ctx->hdr_tbl_lcl) {
dma_free_coherent(ipa3_ctx->pdev, hdr_mem.size, hdr_mem.base,
hdr_mem.phys_base);
@ -327,6 +334,9 @@ int __ipa_commit_hdr_v3_0(void)
ipa3_ctx->hdr_mem.base,
ipa3_ctx->hdr_mem.phys_base);
ipa3_ctx->hdr_mem = hdr_mem;
} else {
dma_free_coherent(ipa3_ctx->pdev, hdr_mem.size,
hdr_mem.base,hdr_mem.phys_base);
}
}
@ -341,10 +351,12 @@ int __ipa_commit_hdr_v3_0(void)
ipa3_ctx->hdr_proc_ctx_mem.base,
ipa3_ctx->hdr_proc_ctx_mem.phys_base);
ipa3_ctx->hdr_proc_ctx_mem = ctx_mem;
} else {
dma_free_coherent(ipa3_ctx->pdev, ctx_mem.size,
ctx_mem.base,ctx_mem.phys_base);
}
}
end:
if (coal_cmd_pyld)
ipahal_destroy_imm_cmd(coal_cmd_pyld);
@ -355,6 +367,12 @@ end:
ipahal_destroy_imm_cmd(hdr_cmd_pyld);
return rc;
failure_hdr_proc:
dma_free_coherent(ipa3_ctx->pdev, hdr_mem.size, hdr_mem.base,
hdr_mem.phys_base);
failure_hdr:
return rc;
}
static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
@ -747,7 +765,7 @@ int __ipa3_del_hdr(u32 hdr_hdl, bool by_user)
return 0;
}
if (entry->is_hdr_proc_ctx) {
if (entry->is_hdr_proc_ctx || entry->proc_ctx) {
dma_unmap_single(ipa3_ctx->pdev,
entry->phys_base,
entry->hdr_len,
@ -1078,6 +1096,7 @@ int ipa3_reset_hdr(bool user_only)
if (ipa3_id_find(entry->id) == NULL) {
mutex_unlock(&ipa3_ctx->lock);
IPAERR_RL("Invalid header ID\n");
WARN_ON_RATELIMIT_IPA(1);
return -EFAULT;
}
@ -1088,6 +1107,7 @@ int ipa3_reset_hdr(bool user_only)
entry->phys_base,
entry->hdr_len,
DMA_TO_DEVICE);
entry->proc_ctx->hdr = NULL;
entry->proc_ctx = NULL;
} else {
/* move the offset entry to free list */
@ -1145,6 +1165,7 @@ int ipa3_reset_hdr(bool user_only)
if (ipa3_id_find(ctx_entry->id) == NULL) {
mutex_unlock(&ipa3_ctx->lock);
IPAERR_RL("Invalid proc header ID\n");
WARN_ON_RATELIMIT_IPA(1);
return -EFAULT;
}

View file

@ -506,11 +506,13 @@ enum ipa3_wdi_polling_mode {
* @page: skb page
* @dma_addr: DMA address of this Rx packet
* @is_tmp_alloc: skb page from tmp_alloc or recycle_list
* @page_order: page order associated with the page.
*/
struct ipa_rx_page_data {
struct page *page;
dma_addr_t dma_addr;
bool is_tmp_alloc;
u32 page_order;
};
struct ipa3_active_client_htable_entry {
@ -544,6 +546,7 @@ struct ipa_smmu_cb_ctx {
u32 va_end;
bool shared;
bool is_cache_coherent;
bool done;
};
/**
@ -1445,6 +1448,7 @@ struct ipa3_stats {
u32 tx_non_linear;
u32 rx_page_drop_cnt;
struct ipa3_page_recycle_stats page_recycle_stats[2];
u64 lower_order;
};
/* offset for each stats */
@ -2124,6 +2128,8 @@ struct ipa3_context {
bool (*get_teth_port_state[IPA_MAX_CLNT])(void);
atomic_t is_ssr;
bool deepsleep;
void *subsystem_get_retval;
struct IpaHwOffloadStatsAllocCmdData_t
gsi_info[IPA_HW_PROTOCOL_MAX];
bool ipa_wan_skb_page;
@ -2155,6 +2161,8 @@ struct ipa3_context {
bool modem_load_ipa_fw;
bool fnr_stats_not_supported;
bool is_device_crashed;
int ipa_pil_load;
};
struct ipa3_plat_drv_res {
@ -2503,7 +2511,6 @@ int ipa3_start_stop_client_prod_gsi_chnl(enum ipa_client_type client,
bool start_chnl);
void ipa3_client_prod_post_shutdown_cleanup(void);
int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset, u32 tmr_val,
enum ipa_client_type client);
@ -2971,6 +2978,7 @@ int ipa3_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status,
void ipa3_uc_register_handlers(enum ipa3_hw_features feature,
struct ipa3_uc_hdlrs *hdlrs);
int ipa3_uc_notify_clk_state(bool enabled);
void ipa3_uc_interface_destroy(void);
int ipa3_dma_setup(void);
void ipa3_dma_shutdown(void);
void ipa3_dma_async_memcpy_notify_cb(void *priv,
@ -3121,6 +3129,7 @@ int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats);
struct dentry *ipa_debugfs_get_root(void);
void ipa3_enable_dcd(void);
void ipa3_disable_prefetch(enum ipa_client_type client);
void ipa3_dealloc_common_event_ring(void);
int ipa3_alloc_common_event_ring(void);
int ipa3_allocate_dma_task_for_gsi(void);
void ipa3_free_dma_task_for_gsi(void);

View file

@ -454,7 +454,9 @@ int ipa3_remove_interrupt_handler(enum ipa_irq_type interrupt)
return -EFAULT;
}
kfree(ipa_interrupt_to_cb[irq_num].private_data);
/*If free ipa3_ctx pointer causing device crash during remove interrupt*/
if(ipa_interrupt_to_cb[irq_num].private_data != ipa3_ctx)
kfree(ipa_interrupt_to_cb[irq_num].private_data);
ipa_interrupt_to_cb[irq_num].deferred_flag = false;
ipa_interrupt_to_cb[irq_num].handler = NULL;
ipa_interrupt_to_cb[irq_num].private_data = NULL;

View file

@ -179,7 +179,7 @@ static int ipa3_nat_ipv6ct_mmap(
/*
* Check if no smmu or non dma coherent
*/
if (!cb->valid || !dev_is_dma_coherent(cb->dev)) {
if (cb && cb->dev && (!cb->valid || !dev_is_dma_coherent(cb->dev))) {
IPADBG("Either smmu valid=%u and/or DMA coherent=%u false\n",
cb->valid, !dev_is_dma_coherent(cb->dev));
@ -1366,8 +1366,9 @@ int ipa3_nat_init_cmd(
goto bail;
}
if (init->table_entries == 0) {
IPAERR_RL("Table entries is zero\n");
if (init->table_entries == 0 ||
init->table_entries == U16_MAX) {
IPAERR_RL("Table entries is %d\n", init->table_entries);
result = -EPERM;
goto bail;
}

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "ipa_i.h"
@ -250,6 +251,7 @@ int ipa3_send_adpl_msg(unsigned long skb_data)
list_add_tail(&msg->link, &ipa3_odl_ctx->adpl_msg_list);
atomic_inc(&ipa3_odl_ctx->stats.numer_in_queue);
mutex_unlock(&ipa3_odl_ctx->adpl_msg_lock);
wake_up(&ipa3_odl_ctx->adpl_msg_waitq);
IPA_STATS_INC_CNT(ipa3_odl_ctx->stats.odl_rx_pkt);
return 0;
@ -283,7 +285,7 @@ int ipa_setup_odl_pipe(void)
ipa_odl_ep_cfg = &ipa3_odl_ctx->odl_sys_param;
IPADBG("Setting up the odl endpoint\n");
ipa_odl_ep_cfg->ipa_ep_cfg.cfg.cs_offload_en = IPA_ENABLE_CS_OFFLOAD_DL;
ipa_odl_ep_cfg->ipa_ep_cfg.cfg.cs_offload_en = IPA_DISABLE_CS_OFFLOAD;
ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_hard_byte_limit_en = 1;
@ -365,6 +367,11 @@ int ipa3_odl_pipe_open(void)
return 0;
}
if (atomic_read(&ipa3_ctx->is_ssr)) {
IPAERR("SSR in progress ODL pipe configuration not allowed\n");
return 0;
}
memset(&holb_cfg, 0, sizeof(holb_cfg));
holb_cfg.tmr_val = 0;
holb_cfg.en = 1;
@ -527,7 +534,9 @@ static ssize_t ipa_adpl_read(struct file *filp, char __user *buf, size_t count,
int ret = 0;
char __user *start = buf;
struct ipa3_push_msg_odl *msg;
DEFINE_WAIT_FUNC(wait, woken_wake_function);
add_wait_queue(&ipa3_odl_ctx->adpl_msg_waitq, &wait);
while (1) {
IPADBG_LOW("Writing message to adpl pipe\n");
if (!ipa3_odl_ctx->odl_state.odl_open)
@ -572,9 +581,6 @@ static ssize_t ipa_adpl_read(struct file *filp, char __user *buf, size_t count,
IPA_STATS_INC_CNT(ipa3_odl_ctx->stats.odl_tx_diag_pkt);
kfree(msg);
msg = NULL;
} else {
ret = -EAGAIN;
break;
}
ret = -EAGAIN;
@ -587,9 +593,9 @@ static ssize_t ipa_adpl_read(struct file *filp, char __user *buf, size_t count,
if (start != buf)
break;
wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
remove_wait_queue(&ipa3_odl_ctx->adpl_msg_waitq, &wait);
if (start != buf && ret != -EFAULT)
ret = buf - start;
@ -665,6 +671,7 @@ int ipa_odl_init(void)
odl_cdev = ipa3_odl_ctx->odl_cdev;
INIT_LIST_HEAD(&ipa3_odl_ctx->adpl_msg_list);
init_waitqueue_head(&ipa3_odl_ctx->adpl_msg_waitq);
mutex_init(&ipa3_odl_ctx->adpl_msg_lock);
mutex_init(&ipa3_odl_ctx->pipe_lock);

View file

@ -58,6 +58,7 @@ struct ipa_odl_context {
bool odl_ctl_msg_wq_flag;
struct ipa3_odlstats stats;
u32 odl_pm_hdl;
wait_queue_head_t adpl_msg_waitq;
};
struct ipa3_push_msg_odl {

View file

@ -27,7 +27,7 @@
#define IPA_Q6_SERVICE_INS_ID 2
#define QMI_SEND_STATS_REQ_TIMEOUT_MS 5000
#define QMI_SEND_REQ_TIMEOUT_MS 60000
#define QMI_SEND_REQ_TIMEOUT_MS 10000
#define QMI_MHI_SEND_REQ_TIMEOUT_MS 1000
#define QMI_IPA_FORCE_CLEAR_DATAPATH_TIMEOUT_MS 1000
@ -467,14 +467,22 @@ static int ipa3_qmi_send_req_wait(struct qmi_handle *client_handle,
struct qmi_txn txn;
int ret;
mutex_lock(&ipa3_qmi_lock);
if (!client_handle) {
mutex_unlock(&ipa3_qmi_lock);
return -EINVAL;
}
ret = qmi_txn_init(client_handle, &txn, resp_desc->ei_array, resp);
if (ret < 0) {
IPAWANERR("QMI txn init failed, ret= %d\n", ret);
mutex_unlock(&ipa3_qmi_lock);
return ret;
}
mutex_lock(&ipa3_qmi_lock);
ret = qmi_send_request(client_handle,
&ipa3_qmi_ctx->server_sq,
&txn,
@ -483,19 +491,16 @@ static int ipa3_qmi_send_req_wait(struct qmi_handle *client_handle,
req_desc->ei_array,
req);
if (unlikely(!ipa_q6_clnt)) {
mutex_unlock(&ipa3_qmi_lock);
return -EINVAL;
}
mutex_unlock(&ipa3_qmi_lock);
if (ret < 0) {
qmi_txn_cancel(&txn);
mutex_unlock(&ipa3_qmi_lock);
return ret;
}
ret = qmi_txn_wait(&txn, msecs_to_jiffies(timeout_ms));
ret = qmi_txn_wait(&txn, msecs_to_jiffies(timeout_ms));
mutex_unlock(&ipa3_qmi_lock);
return ret;
}

View file

@ -1753,7 +1753,7 @@ int __ipa3_del_rt_rule(u32 rule_hdl)
!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) {
IPADBG("Deleting rule from default rt table idx=%u\n",
entry->tbl->idx);
if (entry->tbl->rule_cnt == 1) {
if (entry->tbl->rule_cnt == 1 && !ipa3_ctx->deepsleep) {
IPAERR_RL("Default tbl last rule cannot be deleted\n");
return -EINVAL;
}

View file

@ -1113,6 +1113,17 @@ remap_fail:
return result;
}
void ipa3_uc_interface_destroy(void)
{
if(ipa3_ctx->uc_ctx.uc_inited) {
ipa3_remove_interrupt_handler(IPA_UC_IRQ_2);
ipa3_remove_interrupt_handler(IPA_UC_IRQ_1);
ipa3_remove_interrupt_handler(IPA_UC_IRQ_0);
iounmap(ipa3_ctx->uc_ctx.uc_sram_mmio);
ipa3_ctx->uc_ctx.uc_inited = false;
}
}
/**
* ipa3_uc_send_cmd() - Send a command to the uC
*
@ -1439,7 +1450,7 @@ int ipa3_uc_debug_stats_alloc(
result = ipa3_uc_send_cmd((u32)(cmd.phys_base),
command,
IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS,
false, 10 * HZ);
false, 20 * HZ);
if (result) {
IPAERR("fail to alloc offload stats\n");
goto cleanup;

View file

@ -6332,8 +6332,8 @@ int ipa3_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ep_holb)
ipa3_ctx->ep[clnt_hdl].holb.en = IPA_HOLB_TMR_EN;
ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n,
clnt_hdl, ep_holb);
/* IPA4.5 issue requires HOLB_EN to be written twice */
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5)
/* For targets > IPA_4.0 issue requires HOLB_EN to be written twice */
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n,
clnt_hdl, ep_holb);

View file

@ -2965,6 +2965,9 @@ static int ipa3_lcl_mdm_ssr_notifier_cb(struct notifier_block *this,
}
switch (code) {
#if IS_ENABLED(CONFIG_DEEPSLEEP)
case SUBSYS_BEFORE_DS_ENTRY:
#endif
case SUBSYS_BEFORE_SHUTDOWN:
IPAWANINFO("IPA received MPSS BEFORE_SHUTDOWN\n");
/*Stop netdev first to stop queueing pkts to Q6 */
@ -2986,6 +2989,16 @@ static int ipa3_lcl_mdm_ssr_notifier_cb(struct notifier_block *this,
ipa3_odl_pipe_cleanup(true);
IPAWANINFO("IPA BEFORE_SHUTDOWN handling is complete\n");
break;
#if IS_ENABLED(CONFIG_DEEPSLEEP)
case SUBSYS_AFTER_DS_ENTRY:
IPAWANINFO("IPA Received AFTER DEEPSLEEP ENTRY\n");
if (atomic_read(&rmnet_ipa3_ctx->is_ssr) &&
ipa3_ctx_get_type(IPA_HW_TYPE) < IPA_HW_v4_0)
ipa3_q6_post_shutdown_cleanup();
IPAWANINFO("AFTER DEEPSLEEP ENTRY handling is complete\n");
break;
#endif
case SUBSYS_AFTER_SHUTDOWN:
IPAWANINFO("IPA Received MPSS AFTER_SHUTDOWN\n");
if (atomic_read(&rmnet_ipa3_ctx->is_ssr) &&
@ -2997,6 +3010,20 @@ static int ipa3_lcl_mdm_ssr_notifier_cb(struct notifier_block *this,
IPAWANINFO("IPA AFTER_SHUTDOWN handling is complete\n");
break;
#if IS_ENABLED(CONFIG_DEEPSLEEP)
case SUBSYS_BEFORE_DS_EXIT:
IPAWANINFO("IPA received BEFORE DEEPSLEEP EXIT\n");
if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
/* clean up cached QMI msg/handlers */
ipa3_qmi_service_exit();
ipa3_q6_pre_powerup_cleanup();
}
/* hold a proxy vote for the modem. */
ipa3_proxy_clk_vote(atomic_read(&rmnet_ipa3_ctx->is_ssr));
ipa3_reset_freeze_vote();
IPAWANINFO("BEFORE DEEPSLEEP EXIT handling is complete\n");
break;
#endif
case SUBSYS_BEFORE_POWERUP:
IPAWANINFO("IPA received MPSS BEFORE_POWERUP\n");
if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
@ -3009,6 +3036,9 @@ static int ipa3_lcl_mdm_ssr_notifier_cb(struct notifier_block *this,
ipa3_reset_freeze_vote();
IPAWANINFO("IPA BEFORE_POWERUP handling is complete\n");
break;
#if IS_ENABLED(CONFIG_DEEPSLEEP)
case SUBSYS_AFTER_DS_EXIT:
#endif
case SUBSYS_AFTER_POWERUP:
IPAWANINFO("IPA received MPSS AFTER_POWERUP\n");
if (!atomic_read(&rmnet_ipa3_ctx->is_initialized) &&

View file

@ -215,6 +215,11 @@ int ipa3_teth_bridge_driver_init(void)
{
int res;
if(ipa3_teth_ctx) {
TETH_DBG("Tethering bridge already initlized\n");
return 0;
}
TETH_DBG("Tethering bridge driver init\n");
ipa3_teth_ctx = kzalloc(sizeof(*ipa3_teth_ctx), GFP_KERNEL);
if (!ipa3_teth_ctx)