Merge 7e372e6a9d on remote branch

Change-Id: If4dfb28436ce615564f652ec1bc6ac8e65f72382
This commit is contained in:
Linux Build Service Account 2020-10-08 05:39:14 -07:00
commit 9b3ac407f1
13 changed files with 357 additions and 74 deletions

View file

@ -2768,6 +2768,44 @@ int gsi_write_channel_scratch2_reg(unsigned long chan_hdl,
}
EXPORT_SYMBOL(gsi_write_channel_scratch2_reg);
int gsi_write_wdi3_channel_scratch_6_7_reg(unsigned long chan_hdl,
union __packed gsi_wdi3_channel_scratch_6_7_reg val)
{
struct gsi_chan_ctx *ctx;
if (!gsi_ctx) {
pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
return -GSI_STATUS_NODEV;
}
if (chan_hdl >= gsi_ctx->max_ch) {
GSIERR("bad params chan_hdl=%lu\n", chan_hdl);
return -GSI_STATUS_INVALID_PARAMS;
}
ctx = &gsi_ctx->chan[chan_hdl];
mutex_lock(&ctx->mlock);
ctx->scratch.wdi3.db_addr_wp_lsb = val.wdi3.db_addr_wp_lsb;
ctx->scratch.wdi3.db_addr_wp_msb = val.wdi3.db_addr_wp_msb;
GSIDBG(" scratch value lsb 32 bit here %x0x & %x0x\n",val.wdi3.db_addr_wp_lsb,
ctx->scratch.wdi3.db_addr_wp_lsb );
GSIDBG(" scratch value here %x0x & %x0x\n",val.wdi3.db_addr_wp_msb,
ctx->scratch.wdi3.db_addr_wp_msb );
gsi_writel(val.data.word1, gsi_ctx->base +
GSI_EE_n_GSI_CH_k_SCRATCH_6_OFFS(chan_hdl,
gsi_ctx->per.ee));
gsi_writel(val.data.word2, gsi_ctx->base +
GSI_EE_n_GSI_CH_k_SCRATCH_7_OFFS(chan_hdl,
gsi_ctx->per.ee));
mutex_unlock(&ctx->mlock);
return GSI_STATUS_SUCCESS;
}
EXPORT_SYMBOL(gsi_write_wdi3_channel_scratch_6_7_reg);
static void __gsi_read_channel_scratch(unsigned long chan_hdl,
union __packed gsi_channel_scratch * val)
{
@ -3979,17 +4017,19 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode)
return -GSI_STATUS_UNSUPPORTED_OP;
}
spin_lock_irqsave(&gsi_ctx->slock, flags);
if (atomic_read(&ctx->poll_mode))
curr = GSI_CHAN_MODE_POLL;
else
curr = GSI_CHAN_MODE_CALLBACK;
if (mode == curr) {
GSIDBG("already in requested mode %u chan_hdl=%lu\n",
GSIERR("already in requested mode %u chan_hdl=%lu\n",
curr, chan_hdl);
spin_unlock_irqrestore(&gsi_ctx->slock, flags);
return -GSI_STATUS_UNSUPPORTED_OP;
}
spin_lock_irqsave(&gsi_ctx->slock, flags);
if (curr == GSI_CHAN_MODE_CALLBACK &&
mode == GSI_CHAN_MODE_POLL) {
__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, 0);

View file

@ -850,6 +850,7 @@ struct __packed gsi_11ad_tx_channel_scratch {
* be updated.
* @qmap_id: Rx only, used for setting metadata register in IPA. Read only field
* for MCS. Write for SW.
* @wdi_db_polling_enabled : set to true for cedros and lahaina WA
* @resv: reserved bits.
* @endp_metadata_reg_offset: Rx only, the offset of
* IPA_ENDP_INIT_HDR_METADATA_n of the
@ -858,16 +859,21 @@ struct __packed gsi_11ad_tx_channel_scratch {
* @rx_pkt_offset: Rx only, Since Rx header length is not fixed,
* WLAN host will pass this information to IPA.
* @resv: reserved bits.
* @db_addr_wp_lsb: used to store 32-bit lsb for wdi db polling
* @db_addr_wp_msb: used to store 32-bit msb for wdi db polling
*/
struct __packed gsi_wdi3_channel_scratch {
uint32_t wifi_rp_address_low;
uint32_t wifi_rp_address_high;
uint32_t update_rp_moderation_threshold : 5;
uint32_t qmap_id : 8;
uint32_t reserved1 : 3;
uint32_t wdi_db_polling_enabled : 1;
uint32_t reserved1 : 2;
uint32_t endp_metadata_reg_offset : 16;
uint32_t rx_pkt_offset : 16;
uint32_t reserved2 : 16;
uint32_t db_addr_wp_lsb;
uint32_t db_addr_wp_msb;
};
/**
@ -975,6 +981,19 @@ union __packed gsi_wdi2_channel_scratch2_reg {
} data;
};
struct __packed gsi_wdi3_channel_scratch_6_7 {
uint32_t db_addr_wp_lsb;
uint32_t db_addr_wp_msb;
};
union __packed gsi_wdi3_channel_scratch_6_7_reg {
struct __packed gsi_wdi3_channel_scratch_6_7 wdi3;
struct __packed {
uint32_t word1;
uint32_t word2;
} data;
};
/**
* gsi_mhi_evt_scratch - MHI protocol SW config area of
* event scratch
@ -1780,6 +1799,18 @@ int gsi_write_channel_scratch2_reg(unsigned long chan_hdl,
*/
int gsi_write_wdi3_channel_scratch2_reg(unsigned long chan_hdl,
union __packed gsi_wdi3_channel_scratch2_reg val);
/**
* gsi_write_channel_scratch_reg - Peripheral should call this function to
* write to the scratch 6, 7 reg area of the channel context
*
* @chan_hdl: Client handle previously obtained from
* gsi_alloc_channel
* @val: Value to write
*
* @Return gsi_status
*/
int gsi_write_wdi3_channel_scratch_6_7_reg(unsigned long chan_hdl,
union __packed gsi_wdi3_channel_scratch_6_7_reg val);
/**
* gsi_read_channel_scratch - Peripheral should call this function to

View file

@ -592,6 +592,17 @@
#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff
#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0
#define GSI_EE_n_GSI_CH_k_SCRATCH_6_OFFS(k, n) \
(GSI_GSI_REG_BASE_OFFS + 0x0000f048 + 0x4000 * (n) + 0x80 * (k))
#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff
#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0
#define GSI_EE_n_GSI_CH_k_SCRATCH_7_OFFS(k, n) \
(GSI_GSI_REG_BASE_OFFS + 0x0000f04c + 0x4000 * (n) + 0x80 * (k))
#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff
#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0
#define GSI_EE_n_EV_CH_k_CNTXT_0_OFFS(k, n) \
(GSI_GSI_REG_BASE_OFFS + 0x00010000 + 0x4000 * (n) + 0x80 * (k))
#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000

View file

@ -6152,7 +6152,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p,
atomic_read(&ipa3_ctx->ipa3_active_clients.cnt));
/* move proxy vote for modem on ipa3_post_init */
if (ipa3_ctx->ipa_hw_type != IPA_HW_v4_0)
ipa3_proxy_clk_vote();
ipa3_proxy_clk_vote(false);
/* The following will retrieve and save the gsi fw version */
ipa_save_gsi_ver();
@ -6587,7 +6587,7 @@ static void ipa3_load_ipa_fw(struct work_struct *work)
IPADBG("Loading IPA uC via PIL\n");
/* Unvoting will happen when uC loaded event received. */
ipa3_proxy_clk_vote();
ipa3_proxy_clk_vote(false);
if (ipa3_ctx->uc_fw_file_name)
result = ipa3_pil_load_ipa_fws(
@ -7021,6 +7021,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
ipa3_ctx->rmnet_ctl_enable = resource_p->rmnet_ctl_enable;
ipa3_ctx->tx_wrapper_cache_max_size = get_tx_wrapper_cache_size(
resource_p->tx_wrapper_cache_max_size);
ipa3_ctx->gsi_wdi_db_polling = resource_p->gsi_wdi_db_polling;
if (resource_p->gsi_fw_file_name) {
ipa3_ctx->gsi_fw_file_name =
@ -7284,6 +7285,13 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
result = -ENOMEM;
goto fail_hdr_offset_cache;
}
ipa3_ctx->fnr_stats_cache = kmem_cache_create("IPA_FNR_STATS",
sizeof(struct ipa_ioc_flt_rt_counter_alloc), 0, 0, NULL);
if (!ipa3_ctx->fnr_stats_cache) {
IPAERR(":ipa fnr stats cache create failed\n");
result = -ENOMEM;
goto fail_fnr_stats_cache;
}
ipa3_ctx->hdr_proc_ctx_cache = kmem_cache_create("IPA_HDR_PROC_CTX",
sizeof(struct ipa3_hdr_proc_ctx_entry), 0, 0, NULL);
if (!ipa3_ctx->hdr_proc_ctx_cache) {
@ -7535,6 +7543,8 @@ fail_rt_tbl_cache:
fail_hdr_proc_ctx_offset_cache:
kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_cache);
fail_hdr_proc_ctx_cache:
kmem_cache_destroy(ipa3_ctx->fnr_stats_cache);
fail_fnr_stats_cache:
kmem_cache_destroy(ipa3_ctx->hdr_offset_cache);
fail_hdr_offset_cache:
kmem_cache_destroy(ipa3_ctx->hdr_cache);
@ -7804,7 +7814,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
ipa_drv_res->ipa_endp_delay_wa = false;
ipa_drv_res->skip_ieob_mask_wa = false;
ipa_drv_res->ipa_gpi_event_rp_ddr = false;
ipa_drv_res->gsi_wdi_db_polling = false;
/* Get IPA HW Version */
result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-ver",
&ipa_drv_res->ipa_hw_type);
@ -8053,6 +8063,12 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
ipa_drv_res->rmnet_ctl_enable
? "True" : "False");
ipa_drv_res->gsi_wdi_db_polling =
of_property_read_bool(pdev->dev.of_node,
"qcom,gsi_wdi_db_polling");
IPADBG(": gsi wdi db polling = %s\n",
ipa_drv_res->gsi_wdi_db_polling
? "True" : "False");
result = of_property_read_string(pdev->dev.of_node,
"qcom,use-gsi-ipa-fw", &ipa_drv_res->gsi_fw_file_name);
if (!result)

View file

@ -2716,6 +2716,38 @@ static ssize_t ipa3_enable_ipc_low(struct file *file,
return count;
}
static ssize_t ipa3_read_gsi_wdi3_db_polling(struct file *file,
char __user *buf, size_t count, loff_t *ppos) {
int nbytes;
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"gsi_wdi_db_polling = %d\n",
ipa3_ctx->gsi_wdi_db_polling);
return simple_read_from_buffer(buf, count, ppos, dbg_buff, nbytes);
}
static ssize_t ipa3_write_gsi_wdi3_db_polling(struct file *file,
const char __user *buf, size_t count, loff_t *ppos) {
int ret;
u32 gsi_wdi_db_polling =0;
if (count >= sizeof(dbg_buff))
return -EFAULT;
ret = kstrtou32_from_user(buf, count, 0, &gsi_wdi_db_polling);
if(ret)
return ret;
if(gsi_wdi_db_polling == 1)
ipa3_ctx->gsi_wdi_db_polling = true;
else if(gsi_wdi_db_polling == 0)
ipa3_ctx->gsi_wdi_db_polling = false;
else
IPAERR("Invalid value \n");
return count;
}
static const struct ipa3_debugfs_file debugfs_files[] = {
{
"gen_reg", IPA_READ_ONLY_MODE, NULL, {
@ -2889,6 +2921,11 @@ static const struct ipa3_debugfs_file debugfs_files[] = {
"app_clk_vote_cnt", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_app_clk_vote,
}
},{
"wdi3_db_polling_enable", IPA_READ_WRITE_MODE, NULL, {
.read = ipa3_read_gsi_wdi3_db_polling,
.write = ipa3_write_gsi_wdi3_db_polling,
}
},
};

View file

@ -1937,6 +1937,7 @@ static void ipa3_wq_handle_rx(struct work_struct *work)
if (sys->napi_obj) {
ipa_pm_activate_sync(sys->pm_hdl);
napi_schedule(sys->napi_obj);
IPA_STATS_INC_CNT(sys->napi_sch_cnt);
} else if (IPA_CLIENT_IS_LOW_LAT_CONS(sys->ep->client)) {
ipa_pm_activate_sync(sys->pm_hdl);
tasklet_schedule(&sys->tasklet);
@ -4590,13 +4591,16 @@ void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys)
* or after NAPI poll
*/
clk_off = ipa_pm_activate(sys->pm_hdl);
if (!clk_off && sys->napi_obj)
if (!clk_off && sys->napi_obj) {
napi_schedule(sys->napi_obj);
else if (!clk_off &&
IPA_STATS_INC_CNT(sys->napi_sch_cnt);
} else if (!clk_off &&
IPA_CLIENT_IS_LOW_LAT_CONS(sys->ep->client)) {
tasklet_schedule(&sys->tasklet);
} else
} else {
queue_work(sys->wq, &sys->work);
}
}
static void ipa_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify)
@ -5312,6 +5316,7 @@ start_poll:
if (cnt < weight && ep->sys->len > IPA_DEFAULT_SYS_YELLOW_WM &&
wan_def_sys->len > IPA_DEFAULT_SYS_YELLOW_WM) {
napi_complete(ep->sys->napi_obj);
IPA_STATS_INC_CNT(ep->sys->napi_comp_cnt);
ret = ipa3_rx_switch_to_intr_mode(ep->sys);
if (ret == -GSI_STATUS_PENDING_IRQ &&
napi_reschedule(ep->sys->napi_obj))

View file

@ -491,6 +491,11 @@ enum ipa_icc_type {
#define IPA_ICC_MAX (IPA_ICC_PATH_MAX*IPA_ICC_TYPE_MAX)
enum ipa3_wdi_polling_mode {
IPA_WDI_DB_POLLING_DISABLED,
IPA_WDI_DB_POLLING_ENABLED,
};
/**
* struct ipa_rx_page_data - information needed
* to send to wlan driver on receiving data from ipa hw
@ -988,6 +993,8 @@ struct ipa3_ep_context {
u32 qmi_request_sent;
u32 eot_in_poll_err;
bool ep_delay_set;
void *tr_doorbel_va;
dma_addr_t tr_doorbel_phy;
/* sys MUST be the last element of this struct */
struct ipa3_sys_context *sys;
@ -1100,6 +1107,8 @@ struct ipa3_sys_context {
struct workqueue_struct *repl_wq;
struct ipa3_status_stats *status_stat;
u32 pm_hdl;
unsigned int napi_sch_cnt;
unsigned int napi_comp_cnt;
/* ordering is important - other immutable fields go below */
};
@ -1851,6 +1860,7 @@ struct ipa3_app_clock_vote {
* @rt_rule_cache: routing rule cache
* @hdr_cache: header cache
* @hdr_offset_cache: header offset cache
* @fnr_stats_cache: FnR stats cache
* @hdr_proc_ctx_cache: processing context cache
* @hdr_proc_ctx_offset_cache: processing context offset cache
* @rt_tbl_cache: routing table cache
@ -1955,6 +1965,7 @@ struct ipa3_context {
struct kmem_cache *rt_rule_cache;
struct kmem_cache *hdr_cache;
struct kmem_cache *hdr_offset_cache;
struct kmem_cache *fnr_stats_cache;
struct kmem_cache *hdr_proc_ctx_cache;
struct kmem_cache *hdr_proc_ctx_offset_cache;
struct kmem_cache *rt_tbl_cache;
@ -2122,6 +2133,7 @@ struct ipa3_context {
bool rmnet_ctl_enable;
char *gsi_fw_file_name;
char *uc_fw_file_name;
bool gsi_wdi_db_polling;
};
struct ipa3_plat_drv_res {
@ -2185,6 +2197,7 @@ struct ipa3_plat_drv_res {
const char *gsi_fw_file_name;
const char *uc_fw_file_name;
u32 tx_wrapper_cache_max_size;
bool gsi_wdi_db_polling;
};
/**
@ -2756,7 +2769,7 @@ int ipa3_ctx_get_type(enum ipa_type_mode type);
bool ipa3_ctx_get_flag(enum ipa_flag flag);
u32 ipa3_ctx_get_num_pipes(void);
void ipa3_proxy_clk_vote(void);
void ipa3_proxy_clk_vote(bool is_ssr);
void ipa3_proxy_clk_unvote(void);
bool ipa3_is_client_handle_valid(u32 clnt_hdl);

View file

@ -13,7 +13,7 @@
#define IPA_PM_MAX_EX_CL 64
#define IPA_PM_THRESHOLD_MAX 5
#define IPA_PM_EXCEPTION_MAX 5
#define IPA_PM_DEFERRED_TIMEOUT 10
#define IPA_PM_DEFERRED_TIMEOUT 100
/*
* ipa_pm group names

View file

@ -6918,13 +6918,21 @@ static int __ipa3_alloc_counter_hdl
return id;
}
int ipa3_alloc_counter_id(struct ipa_ioc_flt_rt_counter_alloc *counter)
int ipa3_alloc_counter_id(struct ipa_ioc_flt_rt_counter_alloc *header)
{
int i, unused_cnt, unused_max, unused_start_id;
struct ipa_ioc_flt_rt_counter_alloc *counter;
idr_preload(GFP_KERNEL);
spin_lock(&ipa3_ctx->flt_rt_counters.hdl_lock);
counter = kmem_cache_zalloc(ipa3_ctx->fnr_stats_cache, GFP_KERNEL);
if (!counter) {
IPAERR_RL("failed to alloc fnr stats counter object\n");
spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock);
return -ENOMEM;
}
memcpy(counter, header, sizeof(struct ipa_ioc_flt_rt_counter_alloc));
/* allocate hw counters */
counter->hw_counter.start_id = 0;
counter->hw_counter.end_id = 0;
@ -7024,7 +7032,7 @@ mark_hw_cnt:
unused_start_id = counter->hw_counter.start_id;
if (unused_start_id < 1 ||
unused_start_id > IPA_FLT_RT_HW_COUNTER) {
IPAERR("unexpected hw_counter start id %d\n",
IPAERR_RL("unexpected hw_counter start id %d\n",
unused_start_id);
goto err;
}
@ -7039,7 +7047,7 @@ mark_sw_cnt:
- IPA_FLT_RT_HW_COUNTER;
if (unused_start_id < 1 ||
unused_start_id > IPA_FLT_RT_SW_COUNTER) {
IPAERR("unexpected sw_counter start id %d\n",
IPAERR_RL("unexpected sw_counter start id %d\n",
unused_start_id);
goto err;
}
@ -7051,10 +7059,12 @@ done:
counter->hdl = __ipa3_alloc_counter_hdl(counter);
spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock);
idr_preload_end();
memcpy(header, counter, sizeof(struct ipa_ioc_flt_rt_counter_alloc));
return 0;
err:
counter->hdl = -1;
kmem_cache_free(ipa3_ctx->fnr_stats_cache, counter);
spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock);
idr_preload_end();
return -ENOMEM;
@ -7068,7 +7078,7 @@ void ipa3_counter_remove_hdl(int hdl)
spin_lock(&ipa3_ctx->flt_rt_counters.hdl_lock);
counter = idr_find(&ipa3_ctx->flt_rt_counters.hdl, hdl);
if (counter == NULL) {
IPAERR("unexpected hdl %d\n", hdl);
IPAERR_RL("unexpected hdl %d\n", hdl);
goto err;
}
/* remove counters belong to this hdl, set used back to 0 */
@ -7078,7 +7088,7 @@ void ipa3_counter_remove_hdl(int hdl)
memset(&ipa3_ctx->flt_rt_counters.used_hw + offset,
0, counter->hw_counter.num_counters * sizeof(bool));
} else {
IPAERR("unexpected hdl %d\n", hdl);
IPAERR_RL("unexpected hdl %d\n", hdl);
goto err;
}
offset = counter->sw_counter.start_id - 1 - IPA_FLT_RT_HW_COUNTER;
@ -7087,11 +7097,12 @@ void ipa3_counter_remove_hdl(int hdl)
memset(&ipa3_ctx->flt_rt_counters.used_sw + offset,
0, counter->sw_counter.num_counters * sizeof(bool));
} else {
IPAERR("unexpected hdl %d\n", hdl);
IPAERR_RL("unexpected hdl %d\n", hdl);
goto err;
}
/* remove the handle */
idr_remove(&ipa3_ctx->flt_rt_counters.hdl, hdl);
kmem_cache_free(ipa3_ctx->fnr_stats_cache, counter);
err:
spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock);
}
@ -7108,8 +7119,10 @@ void ipa3_counter_id_remove_all(void)
memset(&ipa3_ctx->flt_rt_counters.used_sw, 0,
sizeof(ipa3_ctx->flt_rt_counters.used_sw));
/* remove all handles */
idr_for_each_entry(&ipa3_ctx->flt_rt_counters.hdl, counter, hdl)
idr_for_each_entry(&ipa3_ctx->flt_rt_counters.hdl, counter, hdl) {
idr_remove(&ipa3_ctx->flt_rt_counters.hdl, hdl);
kmem_cache_free(ipa3_ctx->fnr_stats_cache, counter);
}
spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock);
}
@ -7590,10 +7603,16 @@ void ipa3_proxy_clk_unvote(void)
*
* Return value: none
*/
void ipa3_proxy_clk_vote(void)
void ipa3_proxy_clk_vote(bool is_ssr)
{
if (ipa3_ctx == NULL)
return;
/* Avoid duplicate votes in case we are in SSR even before uC is loaded. */
if (is_ssr && !ipa3_uc_loaded_check()) {
IPADBG("Dup proxy vote. Ignore as uC is not yet loaded\n");
return;
}
mutex_lock(&ipa3_ctx->q6_proxy_clk_vote_mutex);
if (!ipa3_ctx->q6_proxy_clk_vote_valid ||
(ipa3_ctx->q6_proxy_clk_vote_cnt > 0)) {
@ -7653,7 +7672,7 @@ u32 ipa3_get_num_pipes(void)
/**
* ipa3_disable_apps_wan_cons_deaggr()-
* set ipa_ctx->ipa_client_apps_wan_cons_agg_gro
* set ipa3_ctx->ipa_client_apps_wan_cons_agg_gro
*
* Return value: 0 or negative in case of failure
*/
@ -8323,13 +8342,9 @@ static bool ipa3_gsi_channel_is_quite(struct ipa3_ep_context *ep)
bool empty;
gsi_is_channel_empty(ep->gsi_chan_hdl, &empty);
if (!empty) {
if (!empty)
IPADBG("ch %ld not empty\n", ep->gsi_chan_hdl);
/* queue a work to start polling if don't have one */
atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
if (!atomic_read(&ep->sys->curr_polling_state))
__ipa_gsi_irq_rx_scedule_poll(ep->sys);
}
/*Schedule NAPI only from interrupt context to avoid race conditions*/
return empty;
}
@ -8507,6 +8522,16 @@ static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend)
ipa_assert();
}
} else {
if (IPA_CLIENT_IS_APPS_PROD(client) ||
(client == IPA_CLIENT_APPS_WAN_CONS &&
coal_ep_idx != IPA_EP_NOT_ALLOCATED))
goto chan_statrt;
if (!atomic_read(&ep->sys->curr_polling_state)) {
IPADBG("switch ch %ld to callback\n", ep->gsi_chan_hdl);
gsi_config_channel_mode(ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
}
chan_statrt:
res = gsi_start_channel(ep->gsi_chan_hdl);
if (res) {
IPAERR("failed to start LAN channel\n");
@ -8533,12 +8558,7 @@ static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend)
gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL);
if (!ipa3_gsi_channel_is_quite(ep))
return -EAGAIN;
} else if (!atomic_read(&ep->sys->curr_polling_state)) {
IPADBG("switch ch %ld to callback\n", ep->gsi_chan_hdl);
gsi_config_channel_mode(ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
}
return 0;
}

View file

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018 - 2020, The Linux Foundation. All rights reserved.
@ -428,6 +429,13 @@ static int ipa3_setup_wdi3_gsi_channel(u8 is_smmu_enabled,
(1 << 8));
}
/* enable/disable wdi db polling mode based on dt value*/
if (ipa3_ctx->gsi_wdi_db_polling) {
ch_scratch.wdi3.wdi_db_polling_enabled = IPA_WDI_DB_POLLING_ENABLED;
} else {
ch_scratch.wdi3.wdi_db_polling_enabled = IPA_WDI_DB_POLLING_DISABLED;
}
result = gsi_write_channel_scratch(ep->gsi_chan_hdl, ch_scratch);
if (result != GSI_STATUS_SUCCESS) {
IPAERR("failed to write evt ring scratch\n");
@ -446,6 +454,53 @@ fail_smmu_mapping:
return result;
}
static int ipa3_wdi_gsi_db(phys_addr_t* db_addr, struct ipa3_ep_context *ep_ctx)
{
int result = 0;
struct ipa_mem_buffer mem;
union __packed gsi_wdi3_channel_scratch_6_7_reg gsi_ch_scratch;
mem.base = kzalloc(sizeof(int), GFP_KERNEL);
if (!mem.base)
{
IPAERR("failed to alloc memory mem.base\n");
return -ENOMEM;
}
memset(mem.base, 0, sizeof(int));
ep_ctx->tr_doorbel_va = mem.base;
*db_addr = virt_to_phys((void *) mem.base);
mem.phys_base = dma_map_single(ipa3_ctx->pdev, mem.base, sizeof(int), DMA_BIDIRECTIONAL);
ep_ctx->tr_doorbel_phy = mem.phys_base;
IPADBG("db_addr 0x%x, mem.base = 0x%x, mem.phys_base = 0x%x\n", (*db_addr), mem.base, mem.phys_base);
if (dma_mapping_error(ipa3_ctx->pdev, mem.phys_base)) {
IPAERR("failed to do dma mapping\n");
kfree(mem.base);
return -ENOMEM;
}
/* write channel scratch */
memset(&gsi_ch_scratch, 0, sizeof(gsi_ch_scratch));
gsi_ch_scratch.wdi3.db_addr_wp_lsb = (u32)mem.phys_base;
gsi_ch_scratch.wdi3.db_addr_wp_msb = (u32)(mem.phys_base >> 32);
IPADBG("gsi written lsb value 0x%x\n", gsi_ch_scratch.wdi3.db_addr_wp_lsb);
IPADBG("gsi written msb value 0x%x\n", gsi_ch_scratch.wdi3.db_addr_wp_msb);
result = gsi_write_wdi3_channel_scratch_6_7_reg(ep_ctx->gsi_chan_hdl, gsi_ch_scratch);
if (result != GSI_STATUS_SUCCESS) {
IPAERR("gsi_write_channel_scratch failed %d\n",
result);
dma_unmap_single(ipa3_ctx->pdev, ep_ctx->tr_doorbel_phy, sizeof(int), DMA_BIDIRECTIONAL);
kfree(mem.base);
return result;
}
return result;
}
int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
struct ipa_wdi_conn_out_params *out,
ipa_wdi_meter_notifier_cb wdi_notify)
@ -550,15 +605,27 @@ int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
result = -EFAULT;
goto fail;
}
if (gsi_query_channel_db_addr(ep_rx->gsi_chan_hdl,
&gsi_db_addr_low, &gsi_db_addr_high)) {
IPAERR("failed to query gsi rx db addr\n");
result = -EFAULT;
goto fail;
if (ipa3_ctx->gsi_wdi_db_polling) {
out->is_ddr_mapped = true;
result = ipa3_wdi_gsi_db(&(out->rx_uc_db_pa),ep_rx);
if(result){
IPAERR("fail to write db addr \n");
result = -EFAULT;
goto fail;
}
} else {
out->is_ddr_mapped = false;
if (gsi_query_channel_db_addr(ep_rx->gsi_chan_hdl,
&gsi_db_addr_low, &gsi_db_addr_high)) {
IPAERR("failed to query gsi rx db addr\n");
result = -EFAULT;
goto fail;
}
/* only 32 bit lsb is used */
out->rx_uc_db_pa = (phys_addr_t)(gsi_db_addr_low);
}
/* only 32 bit lsb is used */
out->rx_uc_db_pa = (phys_addr_t)(gsi_db_addr_low);
IPADBG("out->rx_uc_db_pa %llu\n", out->rx_uc_db_pa);
IPADBG("out->rx_uc_db_pa 0x%x\n", out->rx_uc_db_pa);
ipa3_install_dflt_flt_rules(ipa_ep_idx_rx);
IPADBG("client %d (ep: %d) connected\n", rx_client,
@ -601,14 +668,24 @@ int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
result = -EFAULT;
goto fail;
}
if (gsi_query_channel_db_addr(ep_tx->gsi_chan_hdl,
&gsi_db_addr_low, &gsi_db_addr_high)) {
IPAERR("failed to query gsi tx db addr\n");
result = -EFAULT;
goto fail;
if (ipa3_ctx->gsi_wdi_db_polling) {
result = ipa3_wdi_gsi_db(&(out->tx_uc_db_pa),ep_tx);
if(result){
IPAERR("fail to write db addr \n");
result = -EFAULT;
goto fail;
}
} else {
if (gsi_query_channel_db_addr(ep_tx->gsi_chan_hdl,
&gsi_db_addr_low, &gsi_db_addr_high)) {
IPAERR("failed to query gsi tx db addr\n");
result = -EFAULT;
goto fail;
}
/* only 32 bit lsb is used */
out->tx_uc_db_pa = (phys_addr_t)(gsi_db_addr_low);
}
/* only 32 bit lsb is used */
out->tx_uc_db_pa = (phys_addr_t)(gsi_db_addr_low);
IPADBG("out->tx_uc_db_pa %llu\n", out->tx_uc_db_pa);
IPADBG("client %d (ep: %d) connected\n", tx_client,
ipa_ep_idx_tx);
@ -690,6 +767,14 @@ int ipa3_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
ep_rx = &ipa3_ctx->ep[ipa_ep_idx_rx];
IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(ipa_ep_idx_tx));
if (ipa3_ctx->gsi_wdi_db_polling) {
IPADBG("gsi_wdi_db_polling enabled, free and unmap ddr addr\n");
dma_unmap_single(ipa3_ctx->pdev, ep_tx->tr_doorbel_phy, sizeof(int), DMA_BIDIRECTIONAL);
dma_unmap_single(ipa3_ctx->pdev, ep_rx->tr_doorbel_phy, sizeof(int), DMA_BIDIRECTIONAL);
kfree(ep_tx->tr_doorbel_va);
kfree(ep_rx->tr_doorbel_va);
}
/* tear down tx pipe */
result = ipa3_reset_gsi_channel(ipa_ep_idx_tx);
if (result != GSI_STATUS_SUCCESS) {

View file

@ -17,6 +17,13 @@ enum ipa_rmnet_ctl_state {
IPA_RMNET_CTL_START, /* rmnet_ctl register + pipe setup */
};
#define IPA_RMNET_CTL_PIPE_NOT_READY (0)
#define IPA_RMNET_CTL_PIPE_TX_READY (1 << 0)
#define IPA_RMNET_CTL_PIPE_RX_READY (1 << 1)
#define IPA_RMNET_CTL_PIPE_READY_ALL (IPA_RMNET_CTL_PIPE_TX_READY | \
IPA_RMNET_CTL_PIPE_RX_READY) /* TX Ready + RX ready */
#define IPA_WWAN_CONS_DESC_FIFO_SZ 256
#define RMNET_CTRL_QUEUE_MAX (2 * IPA_WWAN_CONS_DESC_FIFO_SZ)
@ -44,6 +51,7 @@ struct ipa3_rmnet_ctl_stats {
struct rmnet_ctl_ipa3_context {
struct ipa3_rmnet_ctl_stats stats;
enum ipa_rmnet_ctl_state state;
u8 pipe_state;
struct ipa_sys_connect_params apps_to_ipa_low_lat_ep_cfg;
struct ipa_sys_connect_params ipa_to_apps_low_lat_ep_cfg;
u32 apps_to_ipa3_low_lat_hdl;
@ -105,6 +113,7 @@ int ipa3_rmnet_ctl_init(void)
rmnet_ctl_ipa3_ctx->state = IPA_RMNET_CTL_NOT_REG;
mutex_init(&rmnet_ctl_ipa3_ctx->lock);
spin_lock_init(&rmnet_ctl_ipa3_ctx->tx_lock);
rmnet_ctl_ipa3_ctx->pipe_state = IPA_RMNET_CTL_PIPE_NOT_READY;
return 0;
}
@ -264,6 +273,7 @@ int ipa3_setup_apps_low_lat_cons_pipe(void)
IPADBG("Low lat pipe setup fails\n");
return ret;
}
rmnet_ctl_ipa3_ctx->pipe_state |= IPA_RMNET_CTL_PIPE_RX_READY;
if (rmnet_ctl_ipa3_ctx->cb_info.ready_cb) {
(*(rmnet_ctl_ipa3_ctx->cb_info.ready_cb))
(rmnet_ctl_ipa3_ctx->cb_info.ready_cb_user_data);
@ -331,6 +341,7 @@ int ipa3_setup_apps_low_lat_prod_pipe(void)
IPAERR("failed to config apps low lat prod pipe\n");
return ret;
}
rmnet_ctl_ipa3_ctx->pipe_state |= IPA_RMNET_CTL_PIPE_TX_READY;
return 0;
}
@ -339,36 +350,47 @@ int ipa3_teardown_apps_low_lat_pipes(void)
int ret = 0;
if (rmnet_ctl_ipa3_ctx->state != IPA_RMNET_CTL_PIPE_READY &&
rmnet_ctl_ipa3_ctx->state != IPA_RMNET_CTL_START) {
rmnet_ctl_ipa3_ctx->state != IPA_RMNET_CTL_START &&
rmnet_ctl_ipa3_ctx->pipe_state == IPA_RMNET_CTL_PIPE_NOT_READY) {
IPAERR("rmnet_ctl in bad state %d\n",
rmnet_ctl_ipa3_ctx->state);
return -EFAULT;
}
if (rmnet_ctl_ipa3_ctx->cb_info.stop_cb) {
(*(rmnet_ctl_ipa3_ctx->cb_info.stop_cb))
(rmnet_ctl_ipa3_ctx->cb_info.stop_cb_user_data);
} else {
IPAERR("Invalid stop_cb\n");
return -EFAULT;
if (rmnet_ctl_ipa3_ctx->pipe_state == IPA_RMNET_CTL_PIPE_READY ||
rmnet_ctl_ipa3_ctx->state == IPA_RMNET_CTL_START) {
if (rmnet_ctl_ipa3_ctx->cb_info.stop_cb) {
(*(rmnet_ctl_ipa3_ctx->cb_info.stop_cb))
(rmnet_ctl_ipa3_ctx->cb_info.stop_cb_user_data);
} else {
IPAERR("Invalid stop_cb\n");
return -EFAULT;
}
if (rmnet_ctl_ipa3_ctx->state == IPA_RMNET_CTL_PIPE_READY)
rmnet_ctl_ipa3_ctx->state = IPA_RMNET_CTL_NOT_REG;
else
rmnet_ctl_ipa3_ctx->state = IPA_RMNET_CTL_REGD;
}
if (rmnet_ctl_ipa3_ctx->state == IPA_RMNET_CTL_PIPE_READY)
rmnet_ctl_ipa3_ctx->state = IPA_RMNET_CTL_NOT_REG;
else
rmnet_ctl_ipa3_ctx->state = IPA_RMNET_CTL_REGD;
ret = ipa3_teardown_sys_pipe(
rmnet_ctl_ipa3_ctx->ipa3_to_apps_low_lat_hdl);
if (ret < 0) {
IPAERR("Failed to teardown APPS->IPA low lat pipe\n");
return ret;
if (rmnet_ctl_ipa3_ctx->pipe_state & IPA_RMNET_CTL_PIPE_RX_READY) {
ret = ipa3_teardown_sys_pipe(
rmnet_ctl_ipa3_ctx->ipa3_to_apps_low_lat_hdl);
if (ret < 0) {
IPAERR("Failed to teardown APPS->IPA low lat pipe\n");
return ret;
}
rmnet_ctl_ipa3_ctx->ipa3_to_apps_low_lat_hdl = -1;
rmnet_ctl_ipa3_ctx->pipe_state &= ~IPA_RMNET_CTL_PIPE_RX_READY;
}
rmnet_ctl_ipa3_ctx->ipa3_to_apps_low_lat_hdl = -1;
ret = ipa3_teardown_sys_pipe(
rmnet_ctl_ipa3_ctx->apps_to_ipa3_low_lat_hdl);
if (ret < 0) {
return ret;
IPAERR("Failed to teardown APPS->IPA low lat pipe\n");
if (rmnet_ctl_ipa3_ctx->pipe_state & IPA_RMNET_CTL_PIPE_TX_READY) {
ret = ipa3_teardown_sys_pipe(
rmnet_ctl_ipa3_ctx->apps_to_ipa3_low_lat_hdl);
if (ret < 0) {
return ret;
IPAERR("Failed to teardown APPS->IPA low lat pipe\n");
}
rmnet_ctl_ipa3_ctx->apps_to_ipa3_low_lat_hdl = -1;
rmnet_ctl_ipa3_ctx->pipe_state &= ~IPA_RMNET_CTL_PIPE_TX_READY;
}
rmnet_ctl_ipa3_ctx->apps_to_ipa3_low_lat_hdl = -1;
return ret;
}

View file

@ -2894,7 +2894,7 @@ static int ipa3_lcl_mdm_ssr_notifier_cb(struct notifier_block *this,
ipa3_q6_pre_powerup_cleanup();
}
/* hold a proxy vote for the modem. */
ipa3_proxy_clk_vote();
ipa3_proxy_clk_vote(atomic_read(&rmnet_ipa3_ctx->is_ssr));
ipa3_reset_freeze_vote();
IPAWANINFO("IPA BEFORE_POWERUP handling is complete\n");
break;

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/completion.h>
@ -30,6 +30,9 @@
pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d EXIT\n", __func__, __LINE__)
#define TETH_ERR(fmt, args...) \
pr_err(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
#define TETH_ERR_RL(fmt, args...) \
pr_err_ratelimited_ipa(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, \
__LINE__, ## args);
/**
* struct ipa3_teth_bridge_ctx - Tethering bridge driver context information
@ -65,12 +68,12 @@ static void teth_bridge_ipa_cb(void *priv, enum ipa_dp_evt_type evt,
TETH_DBG_FUNC_ENTRY();
if (evt != IPA_RECEIVE) {
TETH_ERR("unexpected event %d\n", evt);
TETH_ERR_RL("unexpected event %d\n", evt);
WARN_ON(1);
return;
}
TETH_ERR("Unexpected exception packet from USB, dropping packet\n");
TETH_ERR_RL("Unexpected exception packet from USB, dropping packet\n");
dev_kfree_skb_any(skb);
TETH_DBG_FUNC_EXIT();
}