Merge "ipa: use common ring event ring for WLAN MCC pipes in auto config"

This commit is contained in:
Linux Build Service Account 2020-02-20 10:59:12 -08:00 • committed by Gerrit - the friendly Code Review server
commit ff129dbdd6
5 changed files with 156 additions and 22 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -944,6 +944,9 @@ int gsi_register_device(struct gsi_per_props *props, unsigned long *dev_hdl)
__gsi_config_gen_irq(props->ee, ~0,
~GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_BMSK);
gsi_ctx->shared_ch_info.ch_id = gsi_ctx->max_ch;
gsi_ctx->shared_ch_info.evchid = gsi_ctx->max_ev;
gsi_writel(props->intr, gsi_ctx->base +
GSI_EE_n_CNTXT_INTSET_OFFS(gsi_ctx->per.ee));
@ -1801,7 +1804,8 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl,
if (atomic_read(
&gsi_ctx->evtr[props->evt_ring_hdl].chan_ref_cnt) &&
gsi_ctx->evtr[props->evt_ring_hdl].props.exclusive) {
gsi_ctx->evtr[props->evt_ring_hdl].props.exclusive &&
!props->common_evt_ring) {
GSIERR("evt ring=%lu exclusively used by chan_hdl=%p\n",
props->evt_ring_hdl, chan_hdl);
return -GSI_STATUS_UNSUPPORTED_OP;
@ -1870,6 +1874,10 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl,
ctx->user_data = user_data;
*chan_hdl = props->ch_id;
ctx->allocated = true;
if ((props->evt_ring_hdl != ~0) && props->common_evt_ring) {
gsi_ctx->shared_ch_info.ch_id = props->ch_id;
gsi_ctx->shared_ch_info.evchid = props->evt_ring_hdl;
}
ctx->stats.dp.last_timestamp = jiffies_to_msecs(jiffies);
atomic_inc(&gsi_ctx->num_chan);
@ -2375,6 +2383,11 @@ int gsi_dealloc_channel(unsigned long chan_hdl)
atomic_dec(&ctx->evtr->chan_ref_cnt);
atomic_dec(&gsi_ctx->num_chan);
if (gsi_ctx->shared_ch_info.ch_id == chan_hdl) {
gsi_ctx->shared_ch_info.ch_id = gsi_ctx->max_ch;
gsi_ctx->shared_ch_info.evchid = gsi_ctx->max_ev;
}
return GSI_STATUS_SUCCESS;
}
EXPORT_SYMBOL(gsi_dealloc_channel);
@ -2751,6 +2764,7 @@ EXPORT_SYMBOL(gsi_poll_channel);
int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode)
{
struct gsi_chan_ctx *ctx;
struct gsi_chan_ctx *shared_ch_ctx;
enum gsi_chan_mode curr;
unsigned long flags;
@ -2793,13 +2807,39 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode)
mode == GSI_CHAN_MODE_POLL) {
__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, 0);
atomic_set(&ctx->poll_mode, mode);
if ((ctx->props.common_evt_ring) &&
(gsi_ctx->shared_ch_info.ch_id == chan_hdl)) {
atomic_set(&ctx->evtr->chan->poll_mode, mode);
} else if ((ctx->props.common_evt_ring) &&
gsi_ctx->shared_ch_info.evchid ==
ctx->evtr->id) {
shared_ch_ctx =
&gsi_ctx->chan[gsi_ctx->shared_ch_info.ch_id];
if (shared_ch_ctx != NULL)
atomic_set(&shared_ch_ctx->poll_mode, mode);
}
GSIDBG("set gsi_ctx evtr_id %d to %d mode\n",
ctx->evtr->id, mode);
ctx->stats.callback_to_poll++;
}
if (curr == GSI_CHAN_MODE_POLL &&
mode == GSI_CHAN_MODE_CALLBACK) {
atomic_set(&ctx->poll_mode, mode);
if ((ctx->props.common_evt_ring) &&
(gsi_ctx->shared_ch_info.ch_id == chan_hdl)) {
atomic_set(&ctx->evtr->chan->poll_mode, mode);
} else if ((ctx->props.common_evt_ring) &&
gsi_ctx->shared_ch_info.evchid ==
ctx->evtr->id) {
shared_ch_ctx =
&gsi_ctx->chan[gsi_ctx->shared_ch_info.ch_id];
if (shared_ch_ctx != NULL)
atomic_set(&shared_ch_ctx->poll_mode, mode);
}
__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0);
GSIDBG("set gsi_ctx evtr_id %d to %d mode\n",
ctx->evtr->id, mode);
ctx->stats.poll_to_callback++;
}
spin_unlock_irqrestore(&gsi_ctx->slock, flags);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -190,6 +190,11 @@ struct gsi_generic_ee_cmd_debug_stats {
unsigned long halt_channel;
};
struct gsi_shared_chan_info {
uint8_t ch_id;
uint8_t evchid;
};
struct gsi_ctx {
void __iomem *base;
struct device *dev;
@ -213,6 +218,8 @@ struct gsi_ctx {
struct completion gen_ee_cmd_compl;
void *ipc_logbuf;
void *ipc_logbuf_low;
struct gsi_shared_chan_info shared_ch_info;
/*
* The following used only on emulation systems.
*/

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -102,11 +102,14 @@ static int ipa_populate_tag_field(struct ipa3_desc *desc,
struct ipa3_tx_pkt_wrapper *tx_pkt,
struct ipahal_imm_cmd_pyld **tag_pyld_ret);
static int ipa_poll_gsi_pkt(struct ipa3_sys_context *sys,
struct ipa_mem_buffer *mem_info);
struct ipa_mem_buffer *mem_info,
struct gsi_chan_xfer_notify *xfer_notify);
static unsigned long tag_to_pointer_wa(uint64_t tag);
static uint64_t pointer_to_tag_wa(struct ipa3_tx_pkt_wrapper *tx_pkt);
static u32 ipa_adjust_ra_buff_base_sz(u32 aggr_byte_limit);
static bool ipa_update_common_evt_ring(enum ipa_client_type src,
enum ipa_client_type dst);
static void ipa3_wq_write_done_common(struct ipa3_sys_context *sys,
struct ipa3_tx_pkt_wrapper *tx_pkt)
@ -710,20 +713,24 @@ static int ipa3_handle_rx_core(struct ipa3_sys_context *sys, bool process_all,
int ret;
int cnt = 0;
struct ipa_mem_buffer mem_info = { 0 };
struct gsi_chan_xfer_notify notify;
memset(&notify, 0, sizeof(struct gsi_chan_xfer_notify));
while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
!atomic_read(&sys->curr_polling_state))) {
if (cnt && !process_all)
break;
ret = ipa_poll_gsi_pkt(sys, &mem_info);
ret = ipa_poll_gsi_pkt(sys, &mem_info, &notify);
if (ret)
break;
if (IPA_CLIENT_IS_MEMCPY_DMA_CONS(sys->ep->client))
ipa3_dma_memcpy_notify(sys, &mem_info);
else if (IPA_CLIENT_IS_WLAN_CONS(sys->ep->client))
ipa3_wlan_wq_rx_common(sys, mem_info.size);
ipa3_wlan_wq_rx_common(
(struct ipa3_sys_context *)(notify.chan_user_data),
mem_info.size);
else
ipa3_wq_rx_common(sys, mem_info.size);
@ -738,6 +745,8 @@ static int ipa3_handle_rx_core(struct ipa3_sys_context *sys, bool process_all,
static void ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys)
{
int ret;
u32 wlan_ep_idx;
struct ipa3_ep_context *wlan_ep;
if (!atomic_read(&sys->curr_polling_state)) {
IPAERR("already in intr mode\n");
@ -751,6 +760,16 @@ static void ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys)
IPAERR("Failed to switch to intr mode.\n");
goto fail;
}
if (IPA_CLIENT_IS_WLAN_CONS(sys->ep->client)) {
wlan_ep_idx = ipa3_get_ep_mapping(
((sys->ep->client == IPA_CLIENT_WLAN2_CONS) ?
IPA_CLIENT_WLAN3_CONS : IPA_CLIENT_WLAN2_CONS));
if (wlan_ep_idx != IPA_EP_NOT_ALLOCATED &&
ipa3_ctx->ep[wlan_ep_idx].valid == 1) {
wlan_ep = &ipa3_ctx->ep[wlan_ep_idx];
atomic_set(&wlan_ep->sys->curr_polling_state, 0);
}
}
return;
fail:
@ -1182,6 +1201,12 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl)
ipa3_ctx->gsi_evt_comm_ring_rem +=
ep->gsi_mem_info.chan_ring_len;
} else if (ep->gsi_evt_ring_hdl != ~0) {
/* common event ring is used for WLAN2/WLAN3 pipes */
if (IPA_IS_4_0_AUTO_CONFIG() &&
ep->client == IPA_CLIENT_WLAN2_CONS) {
/* Skip resetting the channel. */
goto teardown;
}
result = gsi_reset_evt_ring(ep->gsi_evt_ring_hdl);
if (result != GSI_STATUS_SUCCESS) {
IPAERR("Failed to reset evt ring: %d.\n",
@ -1201,6 +1226,8 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl)
return result;
}
}
teardown:
if (ep->sys->repl_wq)
flush_workqueue(ep->sys->repl_wq);
if (IPA_CLIENT_IS_CONS(ep->client))
@ -3412,8 +3439,21 @@ static void ipa_gsi_irq_tx_notify_cb(struct gsi_chan_xfer_notify *notify)
void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys)
{
bool clk_off;
u32 wlan_ep_idx;
struct ipa3_ep_context *wlan_ep;
atomic_set(&sys->curr_polling_state, 1);
if (IPA_CLIENT_IS_WLAN_CONS(sys->ep->client)) {
wlan_ep_idx = ipa3_get_ep_mapping(
((sys->ep->client == IPA_CLIENT_WLAN2_CONS) ?
IPA_CLIENT_WLAN3_CONS : IPA_CLIENT_WLAN2_CONS));
if (wlan_ep_idx != IPA_EP_NOT_ALLOCATED &&
ipa3_ctx->ep[wlan_ep_idx].valid == 1) {
wlan_ep = &ipa3_ctx->ep[wlan_ep_idx];
/* Set the polling state. */
atomic_set(&wlan_ep->sys->curr_polling_state, 1);
}
}
ipa3_inc_acquire_wakelock();
/*
@ -3463,11 +3503,7 @@ static void ipa_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify)
struct ipa3_rx_pkt_wrapper, link);
rx_pkt_rcvd = (struct ipa3_rx_pkt_wrapper *)notify->xfer_user_data;
if (rx_pkt_expected != rx_pkt_rcvd) {
IPAERR("Pkt was not filled in head of rx buffer.\n");
WARN_ON(1);
return;
}
sys->ep->xfer_notify = *notify;
sys->ep->bytes_xfered_valid = true;
sys->ep->bytes_xfered = notify->bytes_xfered;
sys->ep->phys_base = rx_pkt_rcvd->data.dma_addr;
@ -3534,6 +3570,26 @@ static void ipa_dma_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify)
}
}
static bool ipa_update_common_evt_ring(enum ipa_client_type src,
enum ipa_client_type dst)
{
u32 src_ep_idx, dst_ep_idx;
src_ep_idx = ipa3_get_ep_mapping(src);
dst_ep_idx = ipa3_get_ep_mapping(dst);
if (src_ep_idx != IPA_EP_NOT_ALLOCATED &&
ipa3_ctx->ep[src_ep_idx].valid == 1 &&
dst_ep_idx != IPA_EP_NOT_ALLOCATED &&
ipa3_ctx->ep[dst_ep_idx].valid == 1) {
/* copy event ring handle */
ipa3_ctx->ep[dst_ep_idx].gsi_evt_ring_hdl =
ipa3_ctx->ep[src_ep_idx].gsi_evt_ring_hdl;
return true;
}
return false;
}
int ipa3_alloc_common_event_ring(void)
{
struct gsi_evt_ring_props gsi_evt_ring_props;
@ -3611,6 +3667,13 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
ep->gsi_evt_ring_hdl = ipa3_ctx->gsi_evt_comm_hdl;
} else if (ep->sys->policy != IPA_POLICY_NOINTR_MODE ||
IPA_CLIENT_IS_CONS(ep->client)) {
/* Use common event ring in auto config for WLAN2/WLAN3 pipes */
if (IPA_IS_4_0_AUTO_CONFIG() &&
(ep->client == IPA_CLIENT_WLAN3_CONS) &&
ipa_update_common_evt_ring(IPA_CLIENT_WLAN2_CONS,
ep->client)) {
goto setup_channel;
}
gsi_evt_ring_props.intf = GSI_EVT_CHTYPE_GPI_EV;
gsi_evt_ring_props.intr = GSI_INTR_IRQ;
gsi_evt_ring_props.re_size =
@ -3623,6 +3686,14 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
*/
gsi_evt_ring_props.ring_len = 2 * in->desc_fifo_sz;
/* In Auto config, common event ring is used for WLAN sys pipes.
* Double the event ring size.
*/
if (IPA_IS_4_0_AUTO_CONFIG() &&
IPA_CLIENT_IS_WLAN_CONS(ep->client))
gsi_evt_ring_props.ring_len =
2 * gsi_evt_ring_props.ring_len;
gsi_evt_ring_props.ring_base_vaddr =
dma_alloc_coherent(ipa3_ctx->pdev,
gsi_evt_ring_props.ring_len,
@ -3659,6 +3730,7 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
goto fail_alloc_evt_ring;
}
setup_channel:
memset(&gsi_channel_props, 0, sizeof(gsi_channel_props));
gsi_channel_props.prot = GSI_CHAN_PROT_GPI;
if (IPA_CLIENT_IS_PROD(ep->client)) {
@ -3731,6 +3803,12 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
gsi_channel_props.xfer_cb = ipa_gsi_irq_rx_notify_cb;
if (IPA_CLIENT_IS_MEMCPY_DMA_CONS(ep->client))
gsi_channel_props.xfer_cb = ipa_dma_gsi_irq_rx_notify_cb;
/* In Auto config, common event ring is used for WLAN sys pipes.*/
if (IPA_IS_4_0_AUTO_CONFIG() &&
IPA_CLIENT_IS_WLAN_CONS(ep->client))
gsi_channel_props.common_evt_ring = true;
result = gsi_alloc_channel(&gsi_channel_props, ipa3_ctx->gsi_dev_hdl,
&ep->gsi_chan_hdl);
if (result != GSI_STATUS_SUCCESS)
@ -3814,21 +3892,22 @@ static int ipa_populate_tag_field(struct ipa3_desc *desc,
}
static int ipa_poll_gsi_pkt(struct ipa3_sys_context *sys,
struct ipa_mem_buffer *mem_info)
struct ipa_mem_buffer *mem_info,
struct gsi_chan_xfer_notify *xfer_notify)
{
int ret;
struct gsi_chan_xfer_notify xfer_notify;
struct ipa3_rx_pkt_wrapper *rx_pkt;
if (sys->ep->bytes_xfered_valid) {
mem_info->phys_base = sys->ep->phys_base;
mem_info->size = (u32)sys->ep->bytes_xfered;
sys->ep->bytes_xfered_valid = false;
*xfer_notify = sys->ep->xfer_notify;
return GSI_STATUS_SUCCESS;
}
ret = gsi_poll_channel(sys->ep->gsi_chan_hdl,
&xfer_notify);
xfer_notify);
if (ret == GSI_STATUS_POLL_EMPTY)
return ret;
else if (ret != GSI_STATUS_SUCCESS) {
@ -3837,9 +3916,9 @@ static int ipa_poll_gsi_pkt(struct ipa3_sys_context *sys,
}
rx_pkt = (struct ipa3_rx_pkt_wrapper *)
xfer_notify.xfer_user_data;
(xfer_notify->xfer_user_data);
mem_info->phys_base = rx_pkt->data.dma_addr;
mem_info->size = xfer_notify.bytes_xfered;
mem_info->size = xfer_notify->bytes_xfered;
return ret;
}
@ -3861,6 +3940,7 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight)
struct ipa_mem_buffer mem_info = {0};
static int total_cnt;
struct ipa_active_client_logging_info log;
struct gsi_chan_xfer_notify notify;
IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log, "NAPI");
@ -3869,14 +3949,14 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight)
IPAERR("bad parm 0x%x\n", clnt_hdl);
return cnt;
}
memset(&notify, 0, sizeof(struct gsi_chan_xfer_notify));
ep = &ipa3_ctx->ep[clnt_hdl];
while (cnt < weight &&
atomic_read(&ep->sys->curr_polling_state)) {
atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
ret = ipa_poll_gsi_pkt(ep->sys, &mem_info);
ret = ipa_poll_gsi_pkt(ep->sys, &mem_info, &notify);
if (ret)
break;

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -385,6 +385,10 @@
#define IPA_TZ_UNLOCK_ATTRIBUTE 0x0C0311
#define TZ_MEM_PROTECT_REGION_ID 0x10
#define IPA_IS_4_0_AUTO_CONFIG() \
((ipa3_ctx->ipa_hw_type == IPA_HW_v4_0) && \
(ipa3_ctx->ipa_config_is_auto))
struct ipa3_active_client_htable_entry {
struct hlist_node list;
char id_string[IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN];
@ -728,6 +732,7 @@ struct ipa3_status_stats {
* @gsi_evt_ring_hdl: EP's GSI channel event ring handle
* @gsi_mem_info: EP's GSI channel rings info
* @chan_scratch: EP's GSI channel scratch info
* @xfer_notify: transfer element
* @cfg: EP cionfiguration
* @dst_pipe_index: destination pipe index
* @rt_tbl_idx: routing table index
@ -752,6 +757,7 @@ struct ipa3_ep_context {
unsigned long gsi_evt_ring_hdl;
struct ipa_gsi_ep_mem_info gsi_mem_info;
union __packed gsi_channel_scratch chan_scratch;
struct gsi_chan_xfer_notify xfer_notify;
bool bytes_xfered_valid;
u16 bytes_xfered;
dma_addr_t phys_base;

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -352,7 +352,7 @@ enum gsi_chan_use_db_eng {
*
* @err_cb: error notification callback
* @chan_user_data: cookie used for notifications
*
* @common_evt_ring: Boolean indicating common event ring.
* All the callbacks are in interrupt context
*
*/
@ -373,6 +373,7 @@ struct gsi_chan_props {
void (*xfer_cb)(struct gsi_chan_xfer_notify *notify);
void (*err_cb)(struct gsi_chan_err_notify *notify);
void *chan_user_data;
bool common_evt_ring;
};
enum gsi_xfer_flag {