msm: ipa: Add napi support to rmnet ipa device
Add napi framework to use napi API's to poll embedded data from IPA HW. Change-Id: Icb6ec9d060ca4fb02e95c1e98bded89422bb1fff CRs-Fixed: 1002026 Signed-off-by: Sunil Paidimarri <hisunil@codeaurora.org>
This commit is contained in:
parent
e639e800ed
commit
238f9c0973
15 changed files with 977 additions and 381 deletions
|
@ -10,6 +10,8 @@ Optional:
|
|||
- qcom,ipa-loaduC: indicate that ipa uC should be loaded
|
||||
- qcom,ipa-advertise-sg-support: determine how to respond to a query
|
||||
regarding scatter-gather capability
|
||||
- qcom,ipa-napi-enable: Boolean context flag to indicate whether
|
||||
to enable napi framework or not
|
||||
|
||||
Example:
|
||||
qcom,rmnet-ipa {
|
||||
|
|
|
@ -10,6 +10,8 @@ Optional:
|
|||
- qcom,ipa-loaduC: indicate that ipa uC should be loaded
|
||||
- qcom,ipa-advertise-sg-support: determine how to respond to a query
|
||||
regarding scatter-gather capability
|
||||
- qcom,ipa-napi-enable: Boolean context flag to indicate whether
|
||||
to enable napi framework or not
|
||||
|
||||
Example:
|
||||
qcom,rmnet-ipa3 {
|
||||
|
|
|
@ -2654,6 +2654,37 @@ void ipa_assert(void)
|
|||
BUG();
|
||||
}
|
||||
|
||||
/**
|
||||
* ipa_rx_poll() - Poll the rx packets from IPA HW in the
|
||||
* softirq context
|
||||
*
|
||||
* @budget: number of packets to be polled in single iteration
|
||||
*
|
||||
* Return codes: >= 0 : Actual number of packets polled
|
||||
*
|
||||
*/
|
||||
int ipa_rx_poll(u32 clnt_hdl, int budget)
|
||||
{
|
||||
int ret;
|
||||
|
||||
IPA_API_DISPATCH_RETURN(ipa_rx_poll, clnt_hdl, budget);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ipa_rx_poll);
|
||||
|
||||
/**
|
||||
* ipa_recycle_wan_skb() - Recycle the Wan skb
|
||||
*
|
||||
* @skb: skb that needs to recycle
|
||||
*
|
||||
*/
|
||||
void ipa_recycle_wan_skb(struct sk_buff *skb)
|
||||
{
|
||||
IPA_API_DISPATCH(ipa_recycle_wan_skb, skb);
|
||||
}
|
||||
EXPORT_SYMBOL(ipa_recycle_wan_skb);
|
||||
|
||||
static const struct dev_pm_ops ipa_pm_ops = {
|
||||
.suspend_noirq = ipa_ap_suspend,
|
||||
.resume_noirq = ipa_ap_resume,
|
||||
|
|
|
@ -356,6 +356,10 @@ struct ipa_api_controller {
|
|||
|
||||
void *(*ipa_get_ipc_logbuf_low)(void);
|
||||
|
||||
int (*ipa_rx_poll)(u32 clnt_hdl, int budget);
|
||||
|
||||
void (*ipa_recycle_wan_skb)(struct sk_buff *skb);
|
||||
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IPA
|
||||
|
|
|
@ -77,6 +77,7 @@ static void ipa_dma_memcpy_notify(struct ipa_sys_context *sys,
|
|||
struct sps_iovec *iovec);
|
||||
|
||||
static u32 ipa_adjust_ra_buff_base_sz(u32 aggr_byte_limit);
|
||||
static void ipa_fast_replenish_rx_cache(struct ipa_sys_context *sys);
|
||||
|
||||
static void ipa_wq_write_done_common(struct ipa_sys_context *sys, u32 cnt)
|
||||
{
|
||||
|
@ -761,6 +762,29 @@ static void ipa_sps_irq_tx_no_aggr_notify(struct sps_event_notify *notify)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ipa_poll_pkt() - Poll packet from SPS BAM
|
||||
* return 0 to caller on poll successfully
|
||||
* else -EIO
|
||||
*
|
||||
*/
|
||||
static int ipa_poll_pkt(struct ipa_sys_context *sys,
|
||||
struct sps_iovec *iov)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sps_get_iovec(sys->ep->ep_hdl, iov);
|
||||
if (ret) {
|
||||
IPAERR("sps_get_iovec failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (iov->addr == 0)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipa_handle_rx_core() - The core functionality of packet reception. This
|
||||
* function is read from multiple code paths.
|
||||
|
@ -787,14 +811,10 @@ static int ipa_handle_rx_core(struct ipa_sys_context *sys, bool process_all,
|
|||
if (cnt && !process_all)
|
||||
break;
|
||||
|
||||
ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
|
||||
if (ret) {
|
||||
IPAERR("sps_get_iovec failed %d\n", ret);
|
||||
ret = ipa_poll_pkt(sys, &iov);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (iov.addr == 0)
|
||||
break;
|
||||
if (IPA_CLIENT_IS_MEMCPY_DMA_CONS(sys->ep->client))
|
||||
ipa_dma_memcpy_notify(sys, &iov);
|
||||
else if (IPA_CLIENT_IS_WLAN_CONS(sys->ep->client))
|
||||
|
@ -851,7 +871,8 @@ static void ipa_rx_switch_to_intr_mode(struct ipa_sys_context *sys)
|
|||
goto fail;
|
||||
}
|
||||
atomic_set(&sys->curr_polling_state, 0);
|
||||
ipa_handle_rx_core(sys, true, false);
|
||||
if (!sys->ep->napi_enabled)
|
||||
ipa_handle_rx_core(sys, true, false);
|
||||
ipa_dec_release_wakelock(sys->ep->wakelock_client);
|
||||
return;
|
||||
|
||||
|
@ -965,26 +986,30 @@ static void ipa_sps_irq_rx_notify(struct sps_event_notify *notify)
|
|||
case SPS_EVENT_EOT:
|
||||
if (IPA_CLIENT_IS_APPS_CONS(sys->ep->client))
|
||||
atomic_set(&ipa_ctx->sps_pm.eot_activity, 1);
|
||||
if (!atomic_read(&sys->curr_polling_state)) {
|
||||
ret = sps_get_config(sys->ep->ep_hdl,
|
||||
&sys->ep->connect);
|
||||
if (ret) {
|
||||
IPAERR("sps_get_config() failed %d\n", ret);
|
||||
break;
|
||||
}
|
||||
sys->ep->connect.options = SPS_O_AUTO_ENABLE |
|
||||
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
|
||||
ret = sps_set_config(sys->ep->ep_hdl,
|
||||
&sys->ep->connect);
|
||||
if (ret) {
|
||||
IPAERR("sps_set_config() failed %d\n", ret);
|
||||
break;
|
||||
}
|
||||
ipa_inc_acquire_wakelock(sys->ep->wakelock_client);
|
||||
atomic_set(&sys->curr_polling_state, 1);
|
||||
trace_intr_to_poll(sys->ep->client);
|
||||
queue_work(sys->wq, &sys->work);
|
||||
|
||||
if (atomic_read(&sys->curr_polling_state)) {
|
||||
sys->ep->eot_in_poll_err++;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = sps_get_config(sys->ep->ep_hdl,
|
||||
&sys->ep->connect);
|
||||
if (ret) {
|
||||
IPAERR("sps_get_config() failed %d\n", ret);
|
||||
break;
|
||||
}
|
||||
sys->ep->connect.options = SPS_O_AUTO_ENABLE |
|
||||
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
|
||||
ret = sps_set_config(sys->ep->ep_hdl,
|
||||
&sys->ep->connect);
|
||||
if (ret) {
|
||||
IPAERR("sps_set_config() failed %d\n", ret);
|
||||
break;
|
||||
}
|
||||
ipa_inc_acquire_wakelock(sys->ep->wakelock_client);
|
||||
atomic_set(&sys->curr_polling_state, 1);
|
||||
trace_intr_to_poll(sys->ep->client);
|
||||
queue_work(sys->wq, &sys->work);
|
||||
break;
|
||||
default:
|
||||
IPAERR("received unexpected event id %d\n", notify->event_id);
|
||||
|
@ -1041,6 +1066,58 @@ static void ipa_handle_rx(struct ipa_sys_context *sys)
|
|||
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
|
||||
}
|
||||
|
||||
/**
|
||||
* ipa2_rx_poll() - Poll the rx packets from IPA HW. This
|
||||
* function is exectued in the softirq context
|
||||
*
|
||||
* if input budget is zero, the driver switches back to
|
||||
* interrupt mode
|
||||
*
|
||||
* return number of polled packets, on error 0(zero)
|
||||
*/
|
||||
int ipa2_rx_poll(u32 clnt_hdl, int weight)
|
||||
{
|
||||
struct ipa_ep_context *ep;
|
||||
int ret;
|
||||
int cnt = 0;
|
||||
unsigned int delay = 1;
|
||||
struct sps_iovec iov;
|
||||
|
||||
IPADBG("\n");
|
||||
if (clnt_hdl >= ipa_ctx->ipa_num_pipes ||
|
||||
ipa_ctx->ep[clnt_hdl].valid == 0) {
|
||||
IPAERR("bad parm 0x%x\n", clnt_hdl);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
ep = &ipa_ctx->ep[clnt_hdl];
|
||||
while (cnt < weight &&
|
||||
atomic_read(&ep->sys->curr_polling_state)) {
|
||||
|
||||
ret = ipa_poll_pkt(ep->sys, &iov);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
ipa_wq_rx_common(ep->sys, iov.size);
|
||||
cnt += 5;
|
||||
};
|
||||
|
||||
if (cnt == 0) {
|
||||
ep->inactive_cycles++;
|
||||
ep->client_notify(ep->priv, IPA_CLIENT_COMP_NAPI, 0);
|
||||
|
||||
if (ep->inactive_cycles > 3 || ep->sys->len == 0) {
|
||||
ep->switch_to_intr = true;
|
||||
delay = 0;
|
||||
}
|
||||
queue_delayed_work(ep->sys->wq,
|
||||
&ep->sys->switch_to_intr_work, msecs_to_jiffies(delay));
|
||||
} else
|
||||
ep->inactive_cycles = 0;
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static void switch_to_intr_rx_work_func(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dwork;
|
||||
|
@ -1048,7 +1125,18 @@ static void switch_to_intr_rx_work_func(struct work_struct *work)
|
|||
|
||||
dwork = container_of(work, struct delayed_work, work);
|
||||
sys = container_of(dwork, struct ipa_sys_context, switch_to_intr_work);
|
||||
ipa_handle_rx(sys);
|
||||
|
||||
if (sys->ep->napi_enabled) {
|
||||
if (sys->ep->switch_to_intr) {
|
||||
ipa_rx_switch_to_intr_mode(sys);
|
||||
IPA_ACTIVE_CLIENTS_DEC_SPECIAL("NAPI");
|
||||
sys->ep->switch_to_intr = false;
|
||||
sys->ep->inactive_cycles = 0;
|
||||
} else
|
||||
sys->ep->client_notify(sys->ep->priv,
|
||||
IPA_CLIENT_START_POLL, 0);
|
||||
} else
|
||||
ipa_handle_rx(sys);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1196,6 +1284,7 @@ int ipa2_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl)
|
|||
}
|
||||
|
||||
INIT_LIST_HEAD(&ep->sys->head_desc_list);
|
||||
INIT_LIST_HEAD(&ep->sys->rcycl_list);
|
||||
spin_lock_init(&ep->sys->spinlock);
|
||||
} else {
|
||||
memset(ep->sys, 0, offsetof(struct ipa_sys_context, ep));
|
||||
|
@ -1211,6 +1300,7 @@ int ipa2_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl)
|
|||
ep->valid = 1;
|
||||
ep->client = sys_in->client;
|
||||
ep->client_notify = sys_in->notify;
|
||||
ep->napi_enabled = sys_in->napi_enabled;
|
||||
ep->priv = sys_in->priv;
|
||||
ep->keep_ipa_awake = sys_in->keep_ipa_awake;
|
||||
atomic_set(&ep->avail_fifo_desc,
|
||||
|
@ -1334,9 +1424,7 @@ int ipa2_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl)
|
|||
|
||||
*clnt_hdl = ipa_ep_idx;
|
||||
|
||||
if (nr_cpu_ids > 1 &&
|
||||
(sys_in->client == IPA_CLIENT_APPS_LAN_CONS ||
|
||||
sys_in->client == IPA_CLIENT_APPS_WAN_CONS)) {
|
||||
if (ep->sys->repl_hdlr == ipa_fast_replenish_rx_cache) {
|
||||
ep->sys->repl.capacity = ep->sys->rx_pool_sz + 1;
|
||||
ep->sys->repl.cache = kzalloc(ep->sys->repl.capacity *
|
||||
sizeof(void *), GFP_KERNEL);
|
||||
|
@ -1425,7 +1513,12 @@ int ipa2_teardown_sys_pipe(u32 clnt_hdl)
|
|||
IPA_ACTIVE_CLIENTS_INC_EP(ipa2_get_client_mapping(clnt_hdl));
|
||||
|
||||
ipa_disable_data_path(clnt_hdl);
|
||||
ep->valid = 0;
|
||||
if (ep->napi_enabled) {
|
||||
ep->switch_to_intr = true;
|
||||
do {
|
||||
usleep_range(95, 105);
|
||||
} while (atomic_read(&ep->sys->curr_polling_state));
|
||||
}
|
||||
|
||||
if (IPA_CLIENT_IS_PROD(ep->client)) {
|
||||
do {
|
||||
|
@ -1471,6 +1564,7 @@ int ipa2_teardown_sys_pipe(u32 clnt_hdl)
|
|||
if (!atomic_read(&ipa_ctx->wc_memb.active_clnt_cnt))
|
||||
ipa_cleanup_wlan_rx_common_cache();
|
||||
|
||||
ep->valid = 0;
|
||||
IPA_ACTIVE_CLIENTS_DEC_EP(ipa2_get_client_mapping(clnt_hdl));
|
||||
|
||||
IPADBG("client (ep: %d) disconnected\n", clnt_hdl);
|
||||
|
@ -1721,7 +1815,13 @@ static void ipa_wq_handle_rx(struct work_struct *work)
|
|||
struct ipa_sys_context *sys;
|
||||
|
||||
sys = container_of(work, struct ipa_sys_context, work);
|
||||
ipa_handle_rx(sys);
|
||||
|
||||
if (sys->ep->napi_enabled) {
|
||||
IPA_ACTIVE_CLIENTS_INC_SPECIAL("NAPI");
|
||||
sys->ep->client_notify(sys->ep->priv,
|
||||
IPA_CLIENT_START_POLL, 0);
|
||||
} else
|
||||
ipa_handle_rx(sys);
|
||||
}
|
||||
|
||||
static void ipa_wq_repl_rx(struct work_struct *work)
|
||||
|
@ -2024,6 +2124,63 @@ fail_kmem_cache_alloc:
|
|||
msecs_to_jiffies(1));
|
||||
}
|
||||
|
||||
static void ipa_replenish_rx_cache_recycle(struct ipa_sys_context *sys)
|
||||
{
|
||||
void *ptr;
|
||||
struct ipa_rx_pkt_wrapper *rx_pkt;
|
||||
int ret;
|
||||
int rx_len_cached = 0;
|
||||
|
||||
rx_len_cached = sys->len;
|
||||
|
||||
while (rx_len_cached < sys->rx_pool_sz) {
|
||||
spin_lock_bh(&sys->spinlock);
|
||||
if (list_empty(&sys->rcycl_list))
|
||||
goto fail_kmem_cache_alloc;
|
||||
|
||||
rx_pkt = list_first_entry(&sys->rcycl_list,
|
||||
struct ipa_rx_pkt_wrapper, link);
|
||||
list_del(&rx_pkt->link);
|
||||
spin_unlock_bh(&sys->spinlock);
|
||||
INIT_LIST_HEAD(&rx_pkt->link);
|
||||
ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
|
||||
rx_pkt->data.dma_addr = dma_map_single(ipa_ctx->pdev,
|
||||
ptr, sys->rx_buff_sz, DMA_FROM_DEVICE);
|
||||
if (rx_pkt->data.dma_addr == 0 ||
|
||||
rx_pkt->data.dma_addr == ~0)
|
||||
goto fail_dma_mapping;
|
||||
|
||||
list_add_tail(&rx_pkt->link, &sys->head_desc_list);
|
||||
rx_len_cached = ++sys->len;
|
||||
|
||||
ret = sps_transfer_one(sys->ep->ep_hdl,
|
||||
rx_pkt->data.dma_addr, sys->rx_buff_sz, rx_pkt, 0);
|
||||
|
||||
if (ret) {
|
||||
IPAERR("sps_transfer_one failed %d\n", ret);
|
||||
goto fail_sps_transfer;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
fail_sps_transfer:
|
||||
rx_len_cached = --sys->len;
|
||||
list_del(&rx_pkt->link);
|
||||
INIT_LIST_HEAD(&rx_pkt->link);
|
||||
dma_unmap_single(ipa_ctx->pdev, rx_pkt->data.dma_addr,
|
||||
sys->rx_buff_sz, DMA_FROM_DEVICE);
|
||||
fail_dma_mapping:
|
||||
spin_lock_bh(&sys->spinlock);
|
||||
list_add_tail(&rx_pkt->link, &sys->rcycl_list);
|
||||
INIT_LIST_HEAD(&rx_pkt->link);
|
||||
spin_unlock_bh(&sys->spinlock);
|
||||
fail_kmem_cache_alloc:
|
||||
spin_unlock_bh(&sys->spinlock);
|
||||
if (rx_len_cached == 0)
|
||||
queue_delayed_work(sys->wq, &sys->replenish_rx_work,
|
||||
msecs_to_jiffies(1));
|
||||
}
|
||||
|
||||
static void ipa_fast_replenish_rx_cache(struct ipa_sys_context *sys)
|
||||
{
|
||||
struct ipa_rx_pkt_wrapper *rx_pkt;
|
||||
|
@ -2035,8 +2192,10 @@ static void ipa_fast_replenish_rx_cache(struct ipa_sys_context *sys)
|
|||
curr = atomic_read(&sys->repl.head_idx);
|
||||
|
||||
while (rx_len_cached < sys->rx_pool_sz) {
|
||||
if (curr == atomic_read(&sys->repl.tail_idx))
|
||||
if (curr == atomic_read(&sys->repl.tail_idx)) {
|
||||
queue_work(sys->repl_wq, &sys->repl_work);
|
||||
break;
|
||||
}
|
||||
|
||||
rx_pkt = sys->repl.cache[curr];
|
||||
list_add_tail(&rx_pkt->link, &sys->head_desc_list);
|
||||
|
@ -2107,6 +2266,15 @@ static void ipa_cleanup_rx(struct ipa_sys_context *sys)
|
|||
kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(rx_pkt, r,
|
||||
&sys->rcycl_list, link) {
|
||||
list_del(&rx_pkt->link);
|
||||
dma_unmap_single(ipa_ctx->pdev, rx_pkt->data.dma_addr,
|
||||
sys->rx_buff_sz, DMA_FROM_DEVICE);
|
||||
sys->free_skb(rx_pkt->data.skb);
|
||||
kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
|
||||
}
|
||||
|
||||
if (sys->repl.cache) {
|
||||
head = atomic_read(&sys->repl.head_idx);
|
||||
tail = atomic_read(&sys->repl.tail_idx);
|
||||
|
@ -2471,6 +2639,10 @@ static int ipa_wan_rx_pyld_hdlr(struct sk_buff *skb,
|
|||
IPA_RECEIVE, (unsigned long)(skb));
|
||||
return rc;
|
||||
}
|
||||
if (sys->repl_hdlr == ipa_replenish_rx_cache_recycle) {
|
||||
IPAERR("Recycle should enable only with GRO Aggr\n");
|
||||
ipa_assert();
|
||||
}
|
||||
/*
|
||||
* payload splits across 2 buff or more,
|
||||
* take the start of the payload from prev_skb
|
||||
|
@ -2721,6 +2893,37 @@ void ipa_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data)
|
|||
ep->client_notify(ep->priv, IPA_RECEIVE, (unsigned long)(rx_skb));
|
||||
}
|
||||
|
||||
void ipa2_recycle_wan_skb(struct sk_buff *skb)
|
||||
{
|
||||
struct ipa_rx_pkt_wrapper *rx_pkt;
|
||||
int ep_idx = ipa2_get_ep_mapping(
|
||||
IPA_CLIENT_APPS_WAN_CONS);
|
||||
gfp_t flag = GFP_NOWAIT | __GFP_NOWARN |
|
||||
(ipa_ctx->use_dma_zone ? GFP_DMA : 0);
|
||||
|
||||
if (unlikely(ep_idx == -1)) {
|
||||
IPAERR("dest EP does not exist\n");
|
||||
ipa_assert();
|
||||
}
|
||||
|
||||
rx_pkt = kmem_cache_zalloc(
|
||||
ipa_ctx->rx_pkt_wrapper_cache, flag);
|
||||
if (!rx_pkt)
|
||||
ipa_assert();
|
||||
|
||||
INIT_WORK(&rx_pkt->work, ipa_wq_rx_avail);
|
||||
rx_pkt->sys = ipa_ctx->ep[ep_idx].sys;
|
||||
|
||||
rx_pkt->data.skb = skb;
|
||||
rx_pkt->data.dma_addr = 0;
|
||||
ipa_skb_recycle(rx_pkt->data.skb);
|
||||
skb_reserve(rx_pkt->data.skb, IPA_HEADROOM);
|
||||
INIT_LIST_HEAD(&rx_pkt->link);
|
||||
spin_lock_bh(&rx_pkt->sys->spinlock);
|
||||
list_add_tail(&rx_pkt->link, &rx_pkt->sys->rcycl_list);
|
||||
spin_unlock_bh(&rx_pkt->sys->spinlock);
|
||||
}
|
||||
|
||||
static void ipa_wq_rx_common(struct ipa_sys_context *sys, u32 size)
|
||||
{
|
||||
struct ipa_rx_pkt_wrapper *rx_pkt_expected;
|
||||
|
@ -2858,6 +3061,220 @@ static int ipa_odu_rx_pyld_hdlr(struct sk_buff *rx_skb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ipa_assign_policy_v2(struct ipa_sys_connect_params *in,
|
||||
struct ipa_sys_context *sys)
|
||||
{
|
||||
unsigned long int aggr_byte_limit;
|
||||
|
||||
sys->ep->status.status_en = true;
|
||||
sys->ep->wakelock_client = IPA_WAKELOCK_REF_CLIENT_MAX;
|
||||
if (IPA_CLIENT_IS_PROD(in->client)) {
|
||||
if (!sys->ep->skip_ep_cfg) {
|
||||
sys->policy = IPA_POLICY_NOINTR_MODE;
|
||||
sys->sps_option = SPS_O_AUTO_ENABLE;
|
||||
sys->sps_callback = NULL;
|
||||
sys->ep->status.status_ep = ipa2_get_ep_mapping(
|
||||
IPA_CLIENT_APPS_LAN_CONS);
|
||||
if (IPA_CLIENT_IS_MEMCPY_DMA_PROD(in->client))
|
||||
sys->ep->status.status_en = false;
|
||||
} else {
|
||||
sys->policy = IPA_POLICY_INTR_MODE;
|
||||
sys->sps_option = (SPS_O_AUTO_ENABLE |
|
||||
SPS_O_EOT);
|
||||
sys->sps_callback =
|
||||
ipa_sps_irq_tx_no_aggr_notify;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
aggr_byte_limit =
|
||||
(unsigned long int)IPA_GENERIC_RX_BUFF_SZ(
|
||||
ipa_adjust_ra_buff_base_sz(
|
||||
in->ipa_ep_cfg.aggr.aggr_byte_limit));
|
||||
|
||||
if (in->client == IPA_CLIENT_APPS_LAN_CONS ||
|
||||
in->client == IPA_CLIENT_APPS_WAN_CONS) {
|
||||
sys->policy = IPA_POLICY_INTR_POLL_MODE;
|
||||
sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
|
||||
| SPS_O_ACK_TRANSFERS);
|
||||
sys->sps_callback = ipa_sps_irq_rx_notify;
|
||||
INIT_WORK(&sys->work, ipa_wq_handle_rx);
|
||||
INIT_DELAYED_WORK(&sys->switch_to_intr_work,
|
||||
switch_to_intr_rx_work_func);
|
||||
INIT_DELAYED_WORK(&sys->replenish_rx_work,
|
||||
replenish_rx_work_func);
|
||||
INIT_WORK(&sys->repl_work, ipa_wq_repl_rx);
|
||||
atomic_set(&sys->curr_polling_state, 0);
|
||||
sys->rx_buff_sz = IPA_GENERIC_RX_BUFF_SZ(
|
||||
IPA_GENERIC_RX_BUFF_BASE_SZ) -
|
||||
IPA_HEADROOM;
|
||||
sys->get_skb = ipa_get_skb_ipa_rx_headroom;
|
||||
sys->free_skb = ipa_free_skb_rx;
|
||||
in->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
|
||||
in->ipa_ep_cfg.aggr.aggr = IPA_GENERIC;
|
||||
in->ipa_ep_cfg.aggr.aggr_time_limit =
|
||||
IPA_GENERIC_AGGR_TIME_LIMIT;
|
||||
if (in->client == IPA_CLIENT_APPS_LAN_CONS) {
|
||||
sys->pyld_hdlr = ipa_lan_rx_pyld_hdlr;
|
||||
if (nr_cpu_ids > 1) {
|
||||
sys->repl_hdlr =
|
||||
ipa_fast_replenish_rx_cache;
|
||||
sys->repl_trig_thresh =
|
||||
sys->rx_pool_sz / 8;
|
||||
} else {
|
||||
sys->repl_hdlr =
|
||||
ipa_replenish_rx_cache;
|
||||
}
|
||||
sys->rx_pool_sz =
|
||||
IPA_GENERIC_RX_POOL_SZ;
|
||||
in->ipa_ep_cfg.aggr.aggr_byte_limit =
|
||||
IPA_GENERIC_AGGR_BYTE_LIMIT;
|
||||
in->ipa_ep_cfg.aggr.aggr_pkt_limit =
|
||||
IPA_GENERIC_AGGR_PKT_LIMIT;
|
||||
sys->ep->wakelock_client =
|
||||
IPA_WAKELOCK_REF_CLIENT_LAN_RX;
|
||||
} else if (in->client ==
|
||||
IPA_CLIENT_APPS_WAN_CONS) {
|
||||
sys->pyld_hdlr = ipa_wan_rx_pyld_hdlr;
|
||||
if (in->napi_enabled) {
|
||||
sys->repl_hdlr =
|
||||
ipa_replenish_rx_cache_recycle;
|
||||
sys->rx_pool_sz =
|
||||
IPA_WAN_NAPI_CONS_RX_POOL_SZ;
|
||||
} else {
|
||||
if (nr_cpu_ids > 1) {
|
||||
sys->repl_hdlr =
|
||||
ipa_fast_replenish_rx_cache;
|
||||
sys->repl_trig_thresh =
|
||||
sys->rx_pool_sz / 8;
|
||||
} else {
|
||||
sys->repl_hdlr =
|
||||
ipa_replenish_rx_cache;
|
||||
}
|
||||
sys->rx_pool_sz =
|
||||
ipa_ctx->wan_rx_ring_size;
|
||||
}
|
||||
sys->ep->wakelock_client =
|
||||
IPA_WAKELOCK_REF_CLIENT_WAN_RX;
|
||||
in->ipa_ep_cfg.aggr.aggr_sw_eof_active
|
||||
= true;
|
||||
if (ipa_ctx->ipa_client_apps_wan_cons_agg_gro) {
|
||||
IPAERR("get close-by %u\n",
|
||||
ipa_adjust_ra_buff_base_sz(
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_byte_limit));
|
||||
IPAERR("set rx_buff_sz %lu\n", aggr_byte_limit);
|
||||
/* disable ipa_status */
|
||||
sys->ep->status.
|
||||
status_en = false;
|
||||
sys->rx_buff_sz =
|
||||
IPA_GENERIC_RX_BUFF_SZ(
|
||||
ipa_adjust_ra_buff_base_sz(
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_byte_limit));
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_byte_limit =
|
||||
sys->rx_buff_sz < in->
|
||||
ipa_ep_cfg.aggr.aggr_byte_limit ?
|
||||
IPA_ADJUST_AGGR_BYTE_LIMIT(
|
||||
sys->rx_buff_sz) :
|
||||
IPA_ADJUST_AGGR_BYTE_LIMIT(
|
||||
in->ipa_ep_cfg.
|
||||
aggr.aggr_byte_limit);
|
||||
IPAERR("set aggr_limit %lu\n",
|
||||
(unsigned long int)
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_byte_limit);
|
||||
} else {
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_byte_limit =
|
||||
IPA_GENERIC_AGGR_BYTE_LIMIT;
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_pkt_limit =
|
||||
IPA_GENERIC_AGGR_PKT_LIMIT;
|
||||
}
|
||||
}
|
||||
} else if (IPA_CLIENT_IS_WLAN_CONS(in->client)) {
|
||||
IPADBG("assigning policy to client:%d",
|
||||
in->client);
|
||||
|
||||
sys->ep->status.status_en = false;
|
||||
sys->policy = IPA_POLICY_INTR_POLL_MODE;
|
||||
sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
|
||||
| SPS_O_ACK_TRANSFERS);
|
||||
sys->sps_callback = ipa_sps_irq_rx_notify;
|
||||
INIT_WORK(&sys->work, ipa_wq_handle_rx);
|
||||
INIT_DELAYED_WORK(&sys->switch_to_intr_work,
|
||||
switch_to_intr_rx_work_func);
|
||||
INIT_DELAYED_WORK(&sys->replenish_rx_work,
|
||||
replenish_rx_work_func);
|
||||
atomic_set(&sys->curr_polling_state, 0);
|
||||
sys->rx_buff_sz = IPA_WLAN_RX_BUFF_SZ;
|
||||
sys->rx_pool_sz = in->desc_fifo_sz /
|
||||
sizeof(struct sps_iovec) - 1;
|
||||
if (sys->rx_pool_sz > IPA_WLAN_RX_POOL_SZ)
|
||||
sys->rx_pool_sz = IPA_WLAN_RX_POOL_SZ;
|
||||
sys->pyld_hdlr = NULL;
|
||||
sys->repl_hdlr = ipa_replenish_wlan_rx_cache;
|
||||
sys->get_skb = ipa_get_skb_ipa_rx;
|
||||
sys->free_skb = ipa_free_skb_rx;
|
||||
in->ipa_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
|
||||
sys->ep->wakelock_client =
|
||||
IPA_WAKELOCK_REF_CLIENT_WLAN_RX;
|
||||
} else if (IPA_CLIENT_IS_ODU_CONS(in->client)) {
|
||||
IPADBG("assigning policy to client:%d",
|
||||
in->client);
|
||||
|
||||
sys->ep->status.status_en = false;
|
||||
sys->policy = IPA_POLICY_INTR_POLL_MODE;
|
||||
sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
|
||||
| SPS_O_ACK_TRANSFERS);
|
||||
sys->sps_callback = ipa_sps_irq_rx_notify;
|
||||
INIT_WORK(&sys->work, ipa_wq_handle_rx);
|
||||
INIT_DELAYED_WORK(&sys->switch_to_intr_work,
|
||||
switch_to_intr_rx_work_func);
|
||||
INIT_DELAYED_WORK(&sys->replenish_rx_work,
|
||||
replenish_rx_work_func);
|
||||
atomic_set(&sys->curr_polling_state, 0);
|
||||
sys->rx_buff_sz = IPA_ODU_RX_BUFF_SZ;
|
||||
sys->rx_pool_sz = in->desc_fifo_sz /
|
||||
sizeof(struct sps_iovec) - 1;
|
||||
if (sys->rx_pool_sz > IPA_ODU_RX_POOL_SZ)
|
||||
sys->rx_pool_sz = IPA_ODU_RX_POOL_SZ;
|
||||
sys->pyld_hdlr = ipa_odu_rx_pyld_hdlr;
|
||||
sys->get_skb = ipa_get_skb_ipa_rx;
|
||||
sys->free_skb = ipa_free_skb_rx;
|
||||
sys->repl_hdlr = ipa_replenish_rx_cache;
|
||||
sys->ep->wakelock_client =
|
||||
IPA_WAKELOCK_REF_CLIENT_ODU_RX;
|
||||
} else if (in->client ==
|
||||
IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS) {
|
||||
IPADBG("assigning policy to client:%d",
|
||||
in->client);
|
||||
sys->ep->status.status_en = false;
|
||||
sys->policy = IPA_POLICY_INTR_POLL_MODE;
|
||||
sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
|
||||
| SPS_O_ACK_TRANSFERS);
|
||||
sys->sps_callback = ipa_sps_irq_rx_notify;
|
||||
INIT_WORK(&sys->work, ipa_wq_handle_rx);
|
||||
INIT_DELAYED_WORK(&sys->switch_to_intr_work,
|
||||
switch_to_intr_rx_work_func);
|
||||
} else if (in->client ==
|
||||
IPA_CLIENT_MEMCPY_DMA_SYNC_CONS) {
|
||||
IPADBG("assigning policy to client:%d",
|
||||
in->client);
|
||||
sys->ep->status.status_en = false;
|
||||
sys->policy = IPA_POLICY_NOINTR_MODE;
|
||||
sys->sps_option = SPS_O_AUTO_ENABLE |
|
||||
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
|
||||
} else {
|
||||
IPAERR("Need to install a RX pipe hdlr\n");
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipa_assign_policy(struct ipa_sys_connect_params *in,
|
||||
struct ipa_sys_context *sys)
|
||||
{
|
||||
|
@ -2904,203 +3321,14 @@ static int ipa_assign_policy(struct ipa_sys_connect_params *in,
|
|||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (ipa_ctx->ipa_hw_type >= IPA_HW_v2_0) {
|
||||
sys->ep->status.status_en = true;
|
||||
sys->ep->wakelock_client = IPA_WAKELOCK_REF_CLIENT_MAX;
|
||||
if (IPA_CLIENT_IS_PROD(in->client)) {
|
||||
if (!sys->ep->skip_ep_cfg) {
|
||||
sys->policy = IPA_POLICY_NOINTR_MODE;
|
||||
sys->sps_option = SPS_O_AUTO_ENABLE;
|
||||
sys->sps_callback = NULL;
|
||||
sys->ep->status.status_ep = ipa2_get_ep_mapping(
|
||||
IPA_CLIENT_APPS_LAN_CONS);
|
||||
if (IPA_CLIENT_IS_MEMCPY_DMA_PROD(in->client))
|
||||
sys->ep->status.status_en = false;
|
||||
} else {
|
||||
sys->policy = IPA_POLICY_INTR_MODE;
|
||||
sys->sps_option = (SPS_O_AUTO_ENABLE |
|
||||
SPS_O_EOT);
|
||||
sys->sps_callback =
|
||||
ipa_sps_irq_tx_no_aggr_notify;
|
||||
}
|
||||
} else {
|
||||
if (in->client == IPA_CLIENT_APPS_LAN_CONS ||
|
||||
in->client == IPA_CLIENT_APPS_WAN_CONS) {
|
||||
sys->policy = IPA_POLICY_INTR_POLL_MODE;
|
||||
sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
|
||||
| SPS_O_ACK_TRANSFERS);
|
||||
sys->sps_callback = ipa_sps_irq_rx_notify;
|
||||
INIT_WORK(&sys->work, ipa_wq_handle_rx);
|
||||
INIT_DELAYED_WORK(&sys->switch_to_intr_work,
|
||||
switch_to_intr_rx_work_func);
|
||||
INIT_DELAYED_WORK(&sys->replenish_rx_work,
|
||||
replenish_rx_work_func);
|
||||
INIT_WORK(&sys->repl_work, ipa_wq_repl_rx);
|
||||
atomic_set(&sys->curr_polling_state, 0);
|
||||
sys->rx_buff_sz = IPA_GENERIC_RX_BUFF_SZ(
|
||||
IPA_GENERIC_RX_BUFF_BASE_SZ) -
|
||||
IPA_HEADROOM;
|
||||
sys->get_skb = ipa_get_skb_ipa_rx_headroom;
|
||||
sys->free_skb = ipa_free_skb_rx;
|
||||
in->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR;
|
||||
in->ipa_ep_cfg.aggr.aggr = IPA_GENERIC;
|
||||
in->ipa_ep_cfg.aggr.aggr_time_limit =
|
||||
IPA_GENERIC_AGGR_TIME_LIMIT;
|
||||
if (in->client == IPA_CLIENT_APPS_LAN_CONS) {
|
||||
sys->pyld_hdlr = ipa_lan_rx_pyld_hdlr;
|
||||
sys->rx_pool_sz =
|
||||
IPA_GENERIC_RX_POOL_SZ;
|
||||
in->ipa_ep_cfg.aggr.aggr_byte_limit =
|
||||
IPA_GENERIC_AGGR_BYTE_LIMIT;
|
||||
in->ipa_ep_cfg.aggr.aggr_pkt_limit =
|
||||
IPA_GENERIC_AGGR_PKT_LIMIT;
|
||||
sys->ep->wakelock_client =
|
||||
IPA_WAKELOCK_REF_CLIENT_LAN_RX;
|
||||
} else if (in->client ==
|
||||
IPA_CLIENT_APPS_WAN_CONS) {
|
||||
sys->pyld_hdlr = ipa_wan_rx_pyld_hdlr;
|
||||
sys->rx_pool_sz =
|
||||
ipa_ctx->wan_rx_ring_size;
|
||||
sys->ep->wakelock_client =
|
||||
IPA_WAKELOCK_REF_CLIENT_WAN_RX;
|
||||
in->ipa_ep_cfg.aggr.aggr_sw_eof_active
|
||||
= true;
|
||||
if (ipa_ctx->
|
||||
ipa_client_apps_wan_cons_agg_gro) {
|
||||
IPAERR("get close-by %u\n",
|
||||
ipa_adjust_ra_buff_base_sz(
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_byte_limit));
|
||||
IPAERR("set rx_buff_sz %lu\n",
|
||||
(unsigned long int)
|
||||
IPA_GENERIC_RX_BUFF_SZ(
|
||||
ipa_adjust_ra_buff_base_sz(
|
||||
in->ipa_ep_cfg.
|
||||
aggr.aggr_byte_limit)));
|
||||
/* disable ipa_status */
|
||||
sys->ep->status.
|
||||
status_en = false;
|
||||
sys->rx_buff_sz =
|
||||
IPA_GENERIC_RX_BUFF_SZ(
|
||||
ipa_adjust_ra_buff_base_sz(
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_byte_limit));
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_byte_limit =
|
||||
sys->rx_buff_sz < in->
|
||||
ipa_ep_cfg.aggr.
|
||||
aggr_byte_limit ?
|
||||
IPA_ADJUST_AGGR_BYTE_LIMIT(
|
||||
sys->rx_buff_sz) :
|
||||
IPA_ADJUST_AGGR_BYTE_LIMIT(
|
||||
in->ipa_ep_cfg.
|
||||
aggr.aggr_byte_limit);
|
||||
IPAERR("set aggr_limit %lu\n",
|
||||
(unsigned long int)
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_byte_limit);
|
||||
} else {
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_byte_limit =
|
||||
IPA_GENERIC_AGGR_BYTE_LIMIT;
|
||||
in->ipa_ep_cfg.aggr.
|
||||
aggr_pkt_limit =
|
||||
IPA_GENERIC_AGGR_PKT_LIMIT;
|
||||
}
|
||||
}
|
||||
sys->repl_trig_thresh = sys->rx_pool_sz / 8;
|
||||
if (nr_cpu_ids > 1)
|
||||
sys->repl_hdlr =
|
||||
ipa_fast_replenish_rx_cache;
|
||||
else
|
||||
sys->repl_hdlr = ipa_replenish_rx_cache;
|
||||
} else if (IPA_CLIENT_IS_WLAN_CONS(in->client)) {
|
||||
IPADBG("assigning policy to client:%d",
|
||||
in->client);
|
||||
|
||||
sys->ep->status.status_en = false;
|
||||
sys->policy = IPA_POLICY_INTR_POLL_MODE;
|
||||
sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
|
||||
| SPS_O_ACK_TRANSFERS);
|
||||
sys->sps_callback = ipa_sps_irq_rx_notify;
|
||||
INIT_WORK(&sys->work, ipa_wq_handle_rx);
|
||||
INIT_DELAYED_WORK(&sys->switch_to_intr_work,
|
||||
switch_to_intr_rx_work_func);
|
||||
INIT_DELAYED_WORK(&sys->replenish_rx_work,
|
||||
replenish_rx_work_func);
|
||||
atomic_set(&sys->curr_polling_state, 0);
|
||||
sys->rx_buff_sz = IPA_WLAN_RX_BUFF_SZ;
|
||||
sys->rx_pool_sz = in->desc_fifo_sz/
|
||||
sizeof(struct sps_iovec) - 1;
|
||||
if (sys->rx_pool_sz > IPA_WLAN_RX_POOL_SZ)
|
||||
sys->rx_pool_sz = IPA_WLAN_RX_POOL_SZ;
|
||||
sys->pyld_hdlr = NULL;
|
||||
sys->repl_hdlr = ipa_replenish_wlan_rx_cache;
|
||||
sys->get_skb = ipa_get_skb_ipa_rx;
|
||||
sys->free_skb = ipa_free_skb_rx;
|
||||
in->ipa_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
|
||||
sys->ep->wakelock_client =
|
||||
IPA_WAKELOCK_REF_CLIENT_WLAN_RX;
|
||||
} else if (IPA_CLIENT_IS_ODU_CONS(in->client)) {
|
||||
IPADBG("assigning policy to client:%d",
|
||||
in->client);
|
||||
return 0;
|
||||
} else if (ipa_ctx->ipa_hw_type >= IPA_HW_v2_0)
|
||||
return ipa_assign_policy_v2(in, sys);
|
||||
|
||||
sys->ep->status.status_en = false;
|
||||
sys->policy = IPA_POLICY_INTR_POLL_MODE;
|
||||
sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
|
||||
| SPS_O_ACK_TRANSFERS);
|
||||
sys->sps_callback = ipa_sps_irq_rx_notify;
|
||||
INIT_WORK(&sys->work, ipa_wq_handle_rx);
|
||||
INIT_DELAYED_WORK(&sys->switch_to_intr_work,
|
||||
switch_to_intr_rx_work_func);
|
||||
INIT_DELAYED_WORK(&sys->replenish_rx_work,
|
||||
replenish_rx_work_func);
|
||||
atomic_set(&sys->curr_polling_state, 0);
|
||||
sys->rx_buff_sz = IPA_ODU_RX_BUFF_SZ;
|
||||
sys->rx_pool_sz = in->desc_fifo_sz /
|
||||
sizeof(struct sps_iovec) - 1;
|
||||
if (sys->rx_pool_sz > IPA_ODU_RX_POOL_SZ)
|
||||
sys->rx_pool_sz = IPA_ODU_RX_POOL_SZ;
|
||||
sys->pyld_hdlr = ipa_odu_rx_pyld_hdlr;
|
||||
sys->get_skb = ipa_get_skb_ipa_rx;
|
||||
sys->free_skb = ipa_free_skb_rx;
|
||||
sys->repl_hdlr = ipa_replenish_rx_cache;
|
||||
sys->ep->wakelock_client =
|
||||
IPA_WAKELOCK_REF_CLIENT_ODU_RX;
|
||||
} else if (in->client ==
|
||||
IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS) {
|
||||
IPADBG("assigning policy to client:%d",
|
||||
in->client);
|
||||
sys->ep->status.status_en = false;
|
||||
sys->policy = IPA_POLICY_INTR_POLL_MODE;
|
||||
sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT
|
||||
| SPS_O_ACK_TRANSFERS);
|
||||
sys->sps_callback = ipa_sps_irq_rx_notify;
|
||||
INIT_WORK(&sys->work, ipa_wq_handle_rx);
|
||||
INIT_DELAYED_WORK(&sys->switch_to_intr_work,
|
||||
switch_to_intr_rx_work_func);
|
||||
} else if (in->client ==
|
||||
IPA_CLIENT_MEMCPY_DMA_SYNC_CONS) {
|
||||
IPADBG("assigning policy to client:%d",
|
||||
in->client);
|
||||
sys->ep->status.status_en = false;
|
||||
sys->policy = IPA_POLICY_NOINTR_MODE;
|
||||
sys->sps_option = SPS_O_AUTO_ENABLE |
|
||||
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
|
||||
} else {
|
||||
IPAERR("Need to install a RX pipe hdlr\n");
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
IPAERR("Unsupported HW type %d\n", ipa_ctx->ipa_hw_type);
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
IPAERR("Unsupported HW type %d\n", ipa_ctx->ipa_hw_type);
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#define MTU_BYTE 1500
|
||||
|
||||
#define IPA_MAX_NUM_PIPES 0x14
|
||||
#define IPA_WAN_CONS_DESC_FIFO_SZ 0x5E80
|
||||
#define IPA_WAN_NAPI_CONS_RX_POOL_SZ 3000
|
||||
#define IPA_SYS_DESC_FIFO_SZ 0x2000
|
||||
#define IPA_SYS_TX_DATA_DESC_FIFO_SZ 0x1000
|
||||
#define IPA_LAN_RX_HEADER_LENGTH (2)
|
||||
|
@ -515,6 +517,7 @@ enum ipa_wakelock_ref_client {
|
|||
* @disconnect_in_progress: Indicates client disconnect in progress.
|
||||
* @qmi_request_sent: Indicates whether QMI request to enable clear data path
|
||||
* request is sent or not.
|
||||
* @napi_enabled: when true, IPA call client callback to start polling
|
||||
*/
|
||||
struct ipa_ep_context {
|
||||
int valid;
|
||||
|
@ -546,6 +549,10 @@ struct ipa_ep_context {
|
|||
bool disconnect_in_progress;
|
||||
u32 qmi_request_sent;
|
||||
enum ipa_wakelock_ref_client wakelock_client;
|
||||
bool napi_enabled;
|
||||
bool switch_to_intr;
|
||||
int inactive_cycles;
|
||||
u32 eot_in_poll_err;
|
||||
|
||||
/* sys MUST be the last element of this struct */
|
||||
struct ipa_sys_context *sys;
|
||||
|
@ -603,6 +610,7 @@ struct ipa_sys_context {
|
|||
/* ordering is important - mutable fields go above */
|
||||
struct ipa_ep_context *ep;
|
||||
struct list_head head_desc_list;
|
||||
struct list_head rcycl_list;
|
||||
spinlock_t spinlock;
|
||||
struct workqueue_struct *wq;
|
||||
struct workqueue_struct *repl_wq;
|
||||
|
@ -1929,4 +1937,6 @@ void ipa_inc_acquire_wakelock(enum ipa_wakelock_ref_client ref_client);
|
|||
void ipa_dec_release_wakelock(enum ipa_wakelock_ref_client ref_client);
|
||||
int ipa_iommu_map(struct iommu_domain *domain, unsigned long iova,
|
||||
phys_addr_t paddr, size_t size, int prot);
|
||||
int ipa2_rx_poll(u32 clnt_hdl, int budget);
|
||||
void ipa2_recycle_wan_skb(struct sk_buff *skb);
|
||||
#endif /* _IPA_I_H_ */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2015-2016, 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
|
||||
|
@ -127,6 +127,23 @@ TRACE_EVENT(
|
|||
TP_printk("rx_pkt_cnt=%lu", __entry->rx_pkt_cnt)
|
||||
);
|
||||
|
||||
TRACE_EVENT(
|
||||
rmnet_ipa_netif_rcv_skb,
|
||||
|
||||
TP_PROTO(unsigned long rx_pkt_cnt),
|
||||
|
||||
TP_ARGS(rx_pkt_cnt),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned long, rx_pkt_cnt)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->rx_pkt_cnt = rx_pkt_cnt;
|
||||
),
|
||||
|
||||
TP_printk("rx_pkt_cnt=%lu", __entry->rx_pkt_cnt)
|
||||
);
|
||||
#endif /* _IPA_TRACE_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
|
|
@ -5128,7 +5128,8 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
|
|||
ipa2_set_required_perf_profile;
|
||||
api_ctrl->ipa_get_ipc_logbuf = ipa2_get_ipc_logbuf;
|
||||
api_ctrl->ipa_get_ipc_logbuf_low = ipa2_get_ipc_logbuf_low;
|
||||
|
||||
api_ctrl->ipa_rx_poll = ipa2_rx_poll;
|
||||
api_ctrl->ipa_recycle_wan_skb = ipa2_recycle_wan_skb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@
|
|||
#define IPA_QUOTA_REACH_IF_NAME_MAX_SIZE 64
|
||||
#define IPA_UEVENT_NUM_EVNP 4 /* number of event pointers */
|
||||
|
||||
#define NAPI_WEIGHT 60
|
||||
|
||||
static struct net_device *ipa_netdevs[IPA_WWAN_DEVICE_COUNT];
|
||||
static struct ipa_sys_connect_params apps_to_ipa_ep_cfg, ipa_to_apps_ep_cfg;
|
||||
static u32 qmap_hdr_hdl, dflt_v4_wan_rt_hdl, dflt_v6_wan_rt_hdl;
|
||||
|
@ -76,6 +78,8 @@ static struct mutex ipa_to_apps_pipe_handle_guard;
|
|||
static int wwan_add_ul_flt_rule_to_ipa(void);
|
||||
static int wwan_del_ul_flt_rule_to_ipa(void);
|
||||
static void ipa_wwan_msg_free_cb(void*, u32, u32);
|
||||
static void ipa_rmnet_rx_cb(void *priv);
|
||||
static int ipa_rmnet_poll(struct napi_struct *napi, int budget);
|
||||
|
||||
static void wake_tx_queue(struct work_struct *work);
|
||||
static DECLARE_WORK(ipa_tx_wakequeue_work, wake_tx_queue);
|
||||
|
@ -93,8 +97,10 @@ struct ipa_rmnet_plat_drv_res {
|
|||
bool ipa_rmnet_ssr;
|
||||
bool ipa_loaduC;
|
||||
bool ipa_advertise_sg_support;
|
||||
bool ipa_napi_enable;
|
||||
};
|
||||
|
||||
static struct ipa_rmnet_plat_drv_res ipa_rmnet_res;
|
||||
/**
|
||||
* struct wwan_private - WWAN private data
|
||||
* @net: network interface struct implemented by this driver
|
||||
|
@ -119,6 +125,7 @@ struct wwan_private {
|
|||
spinlock_t lock;
|
||||
struct completion resource_granted_completion;
|
||||
enum wwan_device_status device_status;
|
||||
struct napi_struct napi;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -936,6 +943,9 @@ static int __ipa_wwan_open(struct net_device *dev)
|
|||
if (wwan_ptr->device_status != WWAN_DEVICE_ACTIVE)
|
||||
reinit_completion(&wwan_ptr->resource_granted_completion);
|
||||
wwan_ptr->device_status = WWAN_DEVICE_ACTIVE;
|
||||
|
||||
if (ipa_rmnet_res.ipa_napi_enable)
|
||||
napi_enable(&(wwan_ptr->napi));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -970,6 +980,8 @@ static int __ipa_wwan_close(struct net_device *dev)
|
|||
/* do not close wwan port once up, this causes
|
||||
remote side to hang if tried to open again */
|
||||
reinit_completion(&wwan_ptr->resource_granted_completion);
|
||||
if (ipa_rmnet_res.ipa_napi_enable)
|
||||
napi_disable(&(wwan_ptr->napi));
|
||||
rc = ipa2_deregister_intf(dev->name);
|
||||
if (rc) {
|
||||
IPAWANERR("[%s]: ipa2_deregister_intf failed %d\n",
|
||||
|
@ -1168,39 +1180,50 @@ static void apps_ipa_packet_receive_notify(void *priv,
|
|||
enum ipa_dp_evt_type evt,
|
||||
unsigned long data)
|
||||
{
|
||||
struct sk_buff *skb = (struct sk_buff *)data;
|
||||
struct net_device *dev = (struct net_device *)priv;
|
||||
int result;
|
||||
unsigned int packet_len = skb->len;
|
||||
|
||||
IPAWANDBG("Rx packet was received");
|
||||
if (evt != IPA_RECEIVE) {
|
||||
IPAWANERR("A none IPA_RECEIVE event in wan_ipa_receive\n");
|
||||
return;
|
||||
}
|
||||
if (evt == IPA_RECEIVE) {
|
||||
struct sk_buff *skb = (struct sk_buff *)data;
|
||||
int result;
|
||||
unsigned int packet_len = skb->len;
|
||||
|
||||
skb->dev = ipa_netdevs[0];
|
||||
skb->protocol = htons(ETH_P_MAP);
|
||||
IPAWANDBG("Rx packet was received");
|
||||
skb->dev = ipa_netdevs[0];
|
||||
skb->protocol = htons(ETH_P_MAP);
|
||||
|
||||
if (dev->stats.rx_packets % IPA_WWAN_RX_SOFTIRQ_THRESH == 0) {
|
||||
trace_rmnet_ipa_netifni(dev->stats.rx_packets);
|
||||
result = netif_rx_ni(skb);
|
||||
} else {
|
||||
trace_rmnet_ipa_netifrx(dev->stats.rx_packets);
|
||||
result = netif_rx(skb);
|
||||
}
|
||||
if (ipa_rmnet_res.ipa_napi_enable) {
|
||||
trace_rmnet_ipa_netif_rcv_skb(dev->stats.rx_packets);
|
||||
result = netif_receive_skb(skb);
|
||||
} else {
|
||||
if (dev->stats.rx_packets % IPA_WWAN_RX_SOFTIRQ_THRESH
|
||||
== 0) {
|
||||
trace_rmnet_ipa_netifni(dev->stats.rx_packets);
|
||||
result = netif_rx_ni(skb);
|
||||
} else {
|
||||
trace_rmnet_ipa_netifrx(dev->stats.rx_packets);
|
||||
result = netif_rx(skb);
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
pr_err_ratelimited(DEV_NAME " %s:%d fail on netif_receive_skb\n",
|
||||
__func__, __LINE__);
|
||||
dev->stats.rx_dropped++;
|
||||
}
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += packet_len;
|
||||
} else if (evt == IPA_CLIENT_START_POLL)
|
||||
ipa_rmnet_rx_cb(priv);
|
||||
else if (evt == IPA_CLIENT_COMP_NAPI) {
|
||||
struct wwan_private *wwan_ptr = netdev_priv(dev);
|
||||
|
||||
if (ipa_rmnet_res.ipa_napi_enable)
|
||||
napi_complete(&(wwan_ptr->napi));
|
||||
} else
|
||||
IPAWANERR("Invalid evt %d received in wan_ipa_receive\n", evt);
|
||||
|
||||
if (result) {
|
||||
pr_err_ratelimited(DEV_NAME " %s:%d fail on netif_rx\n",
|
||||
__func__, __LINE__);
|
||||
dev->stats.rx_dropped++;
|
||||
}
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += packet_len;
|
||||
}
|
||||
|
||||
static struct ipa_rmnet_plat_drv_res ipa_rmnet_res = {0, };
|
||||
|
||||
/**
|
||||
* ipa_wwan_ioctl() - I/O control for wwan network driver.
|
||||
*
|
||||
|
@ -1555,9 +1578,17 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
ipa_to_apps_ep_cfg.client = IPA_CLIENT_APPS_WAN_CONS;
|
||||
ipa_to_apps_ep_cfg.notify =
|
||||
apps_ipa_packet_receive_notify;
|
||||
ipa_to_apps_ep_cfg.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
|
||||
ipa_to_apps_ep_cfg.priv = dev;
|
||||
|
||||
ipa_to_apps_ep_cfg.napi_enabled =
|
||||
ipa_rmnet_res.ipa_napi_enable;
|
||||
if (ipa_to_apps_ep_cfg.napi_enabled)
|
||||
ipa_to_apps_ep_cfg.desc_fifo_sz =
|
||||
IPA_WAN_CONS_DESC_FIFO_SZ;
|
||||
else
|
||||
ipa_to_apps_ep_cfg.desc_fifo_sz =
|
||||
IPA_SYS_DESC_FIFO_SZ;
|
||||
|
||||
mutex_lock(&ipa_to_apps_pipe_handle_guard);
|
||||
if (atomic_read(&is_ssr)) {
|
||||
IPAWANDBG("In SSR sequence/recovery\n");
|
||||
|
@ -1899,6 +1930,12 @@ static int get_ipa_rmnet_dts_configuration(struct platform_device *pdev,
|
|||
"qcom,ipa-advertise-sg-support");
|
||||
pr_info("IPA SG support = %s\n",
|
||||
ipa_rmnet_drv_res->ipa_advertise_sg_support ? "True" : "False");
|
||||
|
||||
ipa_rmnet_drv_res->ipa_napi_enable =
|
||||
of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,ipa-napi-enable");
|
||||
pr_info("IPA Napi Enable = %s\n",
|
||||
ipa_rmnet_drv_res->ipa_napi_enable ? "True" : "False");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2044,6 +2081,12 @@ static int ipa_wwan_probe(struct platform_device *pdev)
|
|||
if (ipa_rmnet_res.ipa_advertise_sg_support)
|
||||
dev->hw_features |= NETIF_F_SG;
|
||||
|
||||
/* Enable NAPI support in netdevice. */
|
||||
if (ipa_rmnet_res.ipa_napi_enable) {
|
||||
netif_napi_add(dev, &(wwan_ptr->napi),
|
||||
ipa_rmnet_poll, NAPI_WEIGHT);
|
||||
}
|
||||
|
||||
ret = register_netdev(dev);
|
||||
if (ret) {
|
||||
IPAWANERR("unable to register ipa_netdev %d rc=%d\n",
|
||||
|
@ -2068,6 +2111,8 @@ static int ipa_wwan_probe(struct platform_device *pdev)
|
|||
pr_info("rmnet_ipa completed initialization\n");
|
||||
return 0;
|
||||
config_err:
|
||||
if (ipa_rmnet_res.ipa_napi_enable)
|
||||
netif_napi_del(&(wwan_ptr->napi));
|
||||
unregister_netdev(ipa_netdevs[0]);
|
||||
set_perf_err:
|
||||
ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
|
||||
|
@ -2107,6 +2152,9 @@ setup_a7_qmap_hdr_err:
|
|||
static int ipa_wwan_remove(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct wwan_private *wwan_ptr;
|
||||
|
||||
wwan_ptr = netdev_priv(ipa_netdevs[0]);
|
||||
|
||||
pr_info("rmnet_ipa started deinitialization\n");
|
||||
mutex_lock(&ipa_to_apps_pipe_handle_guard);
|
||||
|
@ -2115,6 +2163,8 @@ static int ipa_wwan_remove(struct platform_device *pdev)
|
|||
IPAWANERR("Failed to teardown IPA->APPS pipe\n");
|
||||
else
|
||||
ipa_to_apps_hdl = -1;
|
||||
if (ipa_rmnet_res.ipa_napi_enable)
|
||||
netif_napi_del(&(wwan_ptr->napi));
|
||||
mutex_unlock(&ipa_to_apps_pipe_handle_guard);
|
||||
unregister_netdev(ipa_netdevs[0]);
|
||||
ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
|
||||
|
@ -2802,6 +2852,31 @@ static void ipa_wwan_msg_free_cb(void *buff, u32 len, u32 type)
|
|||
kfree(buff);
|
||||
}
|
||||
|
||||
static void ipa_rmnet_rx_cb(void *priv)
|
||||
{
|
||||
struct net_device *dev = priv;
|
||||
struct wwan_private *wwan_ptr;
|
||||
|
||||
IPAWANDBG("\n");
|
||||
|
||||
if (dev != ipa_netdevs[0]) {
|
||||
IPAWANERR("Not matching with netdev\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wwan_ptr = netdev_priv(dev);
|
||||
napi_schedule(&(wwan_ptr->napi));
|
||||
}
|
||||
|
||||
static int ipa_rmnet_poll(struct napi_struct *napi, int budget)
|
||||
{
|
||||
int rcvd_pkts = 0;
|
||||
|
||||
rcvd_pkts = ipa_rx_poll(ipa_to_apps_hdl, NAPI_WEIGHT);
|
||||
IPAWANDBG("rcvd packets: %d\n", rcvd_pkts);
|
||||
return rcvd_pkts;
|
||||
}
|
||||
|
||||
late_initcall(ipa_wwan_init);
|
||||
module_exit(ipa_wwan_cleanup);
|
||||
MODULE_DESCRIPTION("WWAN Network Interface");
|
||||
|
|
|
@ -1010,25 +1010,28 @@ static void ipa3_sps_irq_rx_notify(struct sps_event_notify *notify)
|
|||
if (IPA_CLIENT_IS_APPS_CONS(sys->ep->client))
|
||||
atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
|
||||
if (!atomic_read(&sys->curr_polling_state)) {
|
||||
ret = sps_get_config(sys->ep->ep_hdl,
|
||||
&sys->ep->connect);
|
||||
if (ret) {
|
||||
IPAERR("sps_get_config() failed %d\n", ret);
|
||||
break;
|
||||
}
|
||||
sys->ep->connect.options = SPS_O_AUTO_ENABLE |
|
||||
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
|
||||
ret = sps_set_config(sys->ep->ep_hdl,
|
||||
&sys->ep->connect);
|
||||
if (ret) {
|
||||
IPAERR("sps_set_config() failed %d\n", ret);
|
||||
break;
|
||||
}
|
||||
ipa3_inc_acquire_wakelock();
|
||||
atomic_set(&sys->curr_polling_state, 1);
|
||||
trace_intr_to_poll3(sys->ep->client);
|
||||
queue_work(sys->wq, &sys->work);
|
||||
sys->ep->eot_in_poll_err++;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = sps_get_config(sys->ep->ep_hdl,
|
||||
&sys->ep->connect);
|
||||
if (ret) {
|
||||
IPAERR("sps_get_config() failed %d\n", ret);
|
||||
break;
|
||||
}
|
||||
sys->ep->connect.options = SPS_O_AUTO_ENABLE |
|
||||
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
|
||||
ret = sps_set_config(sys->ep->ep_hdl,
|
||||
&sys->ep->connect);
|
||||
if (ret) {
|
||||
IPAERR("sps_set_config() failed %d\n", ret);
|
||||
break;
|
||||
}
|
||||
ipa3_inc_acquire_wakelock();
|
||||
atomic_set(&sys->curr_polling_state, 1);
|
||||
trace_intr_to_poll3(sys->ep->client);
|
||||
queue_work(sys->wq, &sys->work);
|
||||
break;
|
||||
default:
|
||||
IPAERR("received unexpected event id %d\n", notify->event_id);
|
||||
|
@ -1089,7 +1092,18 @@ static void ipa3_switch_to_intr_rx_work_func(struct work_struct *work)
|
|||
|
||||
dwork = container_of(work, struct delayed_work, work);
|
||||
sys = container_of(dwork, struct ipa3_sys_context, switch_to_intr_work);
|
||||
ipa3_handle_rx(sys);
|
||||
|
||||
if (sys->ep->napi_enabled) {
|
||||
if (sys->ep->switch_to_intr) {
|
||||
ipa3_rx_switch_to_intr_mode(sys);
|
||||
IPA_ACTIVE_CLIENTS_DEC_SPECIAL("NAPI");
|
||||
sys->ep->switch_to_intr = false;
|
||||
sys->ep->inactive_cycles = 0;
|
||||
} else
|
||||
sys->ep->client_notify(sys->ep->priv,
|
||||
IPA_CLIENT_START_POLL, 0);
|
||||
} else
|
||||
ipa3_handle_rx(sys);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1217,6 +1231,7 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl)
|
|||
ep->valid = 1;
|
||||
ep->client = sys_in->client;
|
||||
ep->client_notify = sys_in->notify;
|
||||
ep->napi_enabled = sys_in->napi_enabled;
|
||||
ep->priv = sys_in->priv;
|
||||
ep->keep_ipa_awake = sys_in->keep_ipa_awake;
|
||||
atomic_set(&ep->avail_fifo_desc,
|
||||
|
@ -1423,6 +1438,12 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl)
|
|||
IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));
|
||||
|
||||
ipa3_disable_data_path(clnt_hdl);
|
||||
if (ep->napi_enabled) {
|
||||
ep->switch_to_intr = true;
|
||||
do {
|
||||
usleep_range(95, 105);
|
||||
} while (atomic_read(&ep->sys->curr_polling_state));
|
||||
}
|
||||
|
||||
if (IPA_CLIENT_IS_PROD(ep->client)) {
|
||||
do {
|
||||
|
@ -1772,7 +1793,13 @@ static void ipa3_wq_handle_rx(struct work_struct *work)
|
|||
struct ipa3_sys_context *sys;
|
||||
|
||||
sys = container_of(work, struct ipa3_sys_context, work);
|
||||
ipa3_handle_rx(sys);
|
||||
|
||||
if (sys->ep->napi_enabled) {
|
||||
IPA_ACTIVE_CLIENTS_INC_SPECIAL("NAPI");
|
||||
sys->ep->client_notify(sys->ep->priv,
|
||||
IPA_CLIENT_START_POLL, 0);
|
||||
} else
|
||||
ipa3_handle_rx(sys);
|
||||
}
|
||||
|
||||
static void ipa3_wq_repl_rx(struct work_struct *work)
|
||||
|
@ -2717,6 +2744,11 @@ static int ipa3_wan_rx_pyld_hdlr(struct sk_buff *skb,
|
|||
IPA_RECEIVE, (unsigned long)(skb));
|
||||
return rc;
|
||||
}
|
||||
if (sys->repl_hdlr == ipa3_replenish_rx_cache_recycle) {
|
||||
IPAERR("Recycle should enable only with GRO Aggr\n");
|
||||
ipa_assert();
|
||||
}
|
||||
|
||||
/*
|
||||
* payload splits across 2 buff or more,
|
||||
* take the start of the payload from prev_skb
|
||||
|
@ -2909,6 +2941,30 @@ static void ipa3_recycle_rx_wrapper(struct ipa3_rx_pkt_wrapper *rx_pkt)
|
|||
spin_unlock_bh(&rx_pkt->sys->spinlock);
|
||||
}
|
||||
|
||||
void ipa3_recycle_wan_skb(struct sk_buff *skb)
|
||||
{
|
||||
struct ipa3_rx_pkt_wrapper *rx_pkt;
|
||||
int ep_idx = ipa3_get_ep_mapping(
|
||||
IPA_CLIENT_APPS_WAN_CONS);
|
||||
gfp_t flag = GFP_NOWAIT | __GFP_NOWARN;
|
||||
|
||||
if (unlikely(ep_idx == -1)) {
|
||||
IPAERR("dest EP does not exist\n");
|
||||
ipa_assert();
|
||||
}
|
||||
|
||||
rx_pkt = kmem_cache_zalloc(ipa3_ctx->rx_pkt_wrapper_cache,
|
||||
flag);
|
||||
if (!rx_pkt)
|
||||
ipa_assert();
|
||||
|
||||
INIT_WORK(&rx_pkt->work, ipa3_wq_rx_avail);
|
||||
rx_pkt->sys = ipa3_ctx->ep[ep_idx].sys;
|
||||
|
||||
rx_pkt->data.skb = skb;
|
||||
ipa3_recycle_rx_wrapper(rx_pkt);
|
||||
}
|
||||
|
||||
static void ipa3_wq_rx_common(struct ipa3_sys_context *sys, u32 size)
|
||||
{
|
||||
struct ipa3_rx_pkt_wrapper *rx_pkt_expected;
|
||||
|
@ -3123,14 +3179,22 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in,
|
|||
IPA_CLIENT_APPS_WAN_CONS) {
|
||||
sys->pyld_hdlr = ipa3_wan_rx_pyld_hdlr;
|
||||
sys->free_rx_wrapper = ipa3_free_rx_wrapper;
|
||||
if (nr_cpu_ids > 1)
|
||||
if (in->napi_enabled) {
|
||||
sys->repl_hdlr =
|
||||
ipa3_fast_replenish_rx_cache;
|
||||
else
|
||||
sys->repl_hdlr =
|
||||
ipa3_replenish_rx_cache;
|
||||
sys->rx_pool_sz =
|
||||
ipa3_ctx->wan_rx_ring_size;
|
||||
ipa3_replenish_rx_cache_recycle;
|
||||
sys->rx_pool_sz =
|
||||
IPA_WAN_NAPI_CONS_RX_POOL_SZ;
|
||||
} else {
|
||||
if (nr_cpu_ids > 1) {
|
||||
sys->repl_hdlr =
|
||||
ipa3_fast_replenish_rx_cache;
|
||||
} else {
|
||||
sys->repl_hdlr =
|
||||
ipa3_replenish_rx_cache;
|
||||
}
|
||||
sys->rx_pool_sz =
|
||||
ipa3_ctx->wan_rx_ring_size;
|
||||
}
|
||||
in->ipa_ep_cfg.aggr.aggr_sw_eof_active
|
||||
= true;
|
||||
if (ipa3_ctx->
|
||||
|
@ -3941,68 +4005,40 @@ static int ipa_populate_tag_field(struct ipa3_desc *desc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ipa_poll_gsi_pkt(struct ipa3_sys_context *sys,
|
||||
struct ipa_mem_buffer *mem_info)
|
||||
{
|
||||
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;
|
||||
return GSI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ret = gsi_poll_channel(sys->ep->gsi_chan_hdl,
|
||||
&xfer_notify);
|
||||
if (ret == GSI_STATUS_POLL_EMPTY)
|
||||
return ret;
|
||||
else if (ret != GSI_STATUS_SUCCESS) {
|
||||
IPAERR("Poll channel err: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rx_pkt = (struct ipa3_rx_pkt_wrapper *)
|
||||
xfer_notify.xfer_user_data;
|
||||
mem_info->phys_base = rx_pkt->data.dma_addr;
|
||||
mem_info->size = xfer_notify.bytes_xfered;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ipa_handle_rx_core_gsi(struct ipa3_sys_context *sys,
|
||||
bool process_all, bool in_poll_state)
|
||||
{
|
||||
int ret;
|
||||
int cnt = 0;
|
||||
struct ipa3_sys_context *sys_ptr;
|
||||
struct ipa3_rx_pkt_wrapper *rx_pkt;
|
||||
struct gsi_chan_xfer_notify xfer_notify;
|
||||
struct ipa_mem_buffer mem_info = {0};
|
||||
enum ipa_client_type client;
|
||||
|
||||
if (sys->ep->bytes_xfered_valid) {
|
||||
mem_info.phys_base = sys->ep->phys_base;
|
||||
mem_info.size = (u32)sys->ep->bytes_xfered;
|
||||
sys_ptr = sys;
|
||||
if (IPA_CLIENT_IS_MEMCPY_DMA_CONS(sys->ep->client))
|
||||
ipa3_dma_memcpy_notify(sys_ptr, &mem_info);
|
||||
else if (IPA_CLIENT_IS_WLAN_CONS(sys->ep->client))
|
||||
ipa3_wlan_wq_rx_common(sys_ptr, mem_info.size);
|
||||
else
|
||||
ipa3_wq_rx_common(sys_ptr, mem_info.size);
|
||||
|
||||
cnt++;
|
||||
sys->ep->bytes_xfered_valid = false;
|
||||
}
|
||||
|
||||
while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
|
||||
!atomic_read(&sys->curr_polling_state))) {
|
||||
if (cnt && !process_all)
|
||||
break;
|
||||
|
||||
ret = gsi_poll_channel(sys->ep->gsi_chan_hdl,
|
||||
&xfer_notify);
|
||||
if (ret == GSI_STATUS_POLL_EMPTY)
|
||||
break;
|
||||
else if (ret == GSI_STATUS_SUCCESS) {
|
||||
sys_ptr = (struct ipa3_sys_context *)
|
||||
xfer_notify.chan_user_data;
|
||||
rx_pkt = (struct ipa3_rx_pkt_wrapper *)
|
||||
xfer_notify.xfer_user_data;
|
||||
mem_info.phys_base = rx_pkt->data.dma_addr;
|
||||
mem_info.size = xfer_notify.bytes_xfered;
|
||||
|
||||
client = sys->ep->client;
|
||||
if (IPA_CLIENT_IS_MEMCPY_DMA_CONS(client))
|
||||
ipa3_dma_memcpy_notify(sys_ptr, &mem_info);
|
||||
else if (IPA_CLIENT_IS_WLAN_CONS(client))
|
||||
ipa3_wlan_wq_rx_common(sys_ptr, mem_info.size);
|
||||
else
|
||||
ipa3_wq_rx_common(sys_ptr, mem_info.size);
|
||||
|
||||
cnt++;
|
||||
} else
|
||||
IPAERR("Poll channel err: %d\n", ret);
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int ipa_handle_rx_core_sps(struct ipa3_sys_context *sys,
|
||||
bool process_all, bool in_poll_state)
|
||||
{
|
||||
struct sps_iovec iov;
|
||||
int ret;
|
||||
int cnt = 0;
|
||||
struct ipa_mem_buffer mem_info = {0};
|
||||
|
@ -4012,17 +4048,10 @@ static int ipa_handle_rx_core_sps(struct ipa3_sys_context *sys,
|
|||
if (cnt && !process_all)
|
||||
break;
|
||||
|
||||
ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
|
||||
if (ret) {
|
||||
IPAERR("sps_get_iovec failed %d\n", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
if (iov.addr == 0)
|
||||
ret = ipa_poll_gsi_pkt(sys, &mem_info);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
mem_info.phys_base = iov.addr;
|
||||
mem_info.size = iov.size;
|
||||
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))
|
||||
|
@ -4035,6 +4064,112 @@ static int ipa_handle_rx_core_sps(struct ipa3_sys_context *sys,
|
|||
return cnt;
|
||||
}
|
||||
|
||||
static int ipa_poll_sps_pkt(struct ipa3_sys_context *sys,
|
||||
struct ipa_mem_buffer *mem_info)
|
||||
{
|
||||
int ret;
|
||||
struct sps_iovec iov;
|
||||
|
||||
ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
|
||||
if (ret) {
|
||||
IPAERR("sps_get_iovec failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (iov.addr == 0)
|
||||
return -EIO;
|
||||
|
||||
mem_info->phys_base = iov.addr;
|
||||
mem_info->size = iov.size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipa_handle_rx_core_sps(struct ipa3_sys_context *sys,
|
||||
bool process_all, bool in_poll_state)
|
||||
{
|
||||
int ret;
|
||||
int cnt = 0;
|
||||
struct ipa_mem_buffer mem_info = {0};
|
||||
|
||||
while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
|
||||
!atomic_read(&sys->curr_polling_state))) {
|
||||
if (cnt && !process_all)
|
||||
break;
|
||||
|
||||
ret = ipa_poll_sps_pkt(sys, &mem_info);
|
||||
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);
|
||||
else
|
||||
ipa3_wq_rx_common(sys, mem_info.size);
|
||||
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipa3_rx_poll() - Poll the rx packets from IPA HW. This
|
||||
* function is exectued in the softirq context
|
||||
*
|
||||
* if input budget is zero, the driver switches back to
|
||||
* interrupt mode
|
||||
*
|
||||
* return number of polled packets, on error 0(zero)
|
||||
*/
|
||||
int ipa3_rx_poll(u32 clnt_hdl, int weight)
|
||||
{
|
||||
struct ipa3_ep_context *ep;
|
||||
int ret;
|
||||
int cnt = 0;
|
||||
unsigned int delay = 1;
|
||||
struct ipa_mem_buffer mem_info = {0};
|
||||
|
||||
IPADBG("\n");
|
||||
if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
|
||||
ipa3_ctx->ep[clnt_hdl].valid == 0) {
|
||||
IPAERR("bad parm 0x%x\n", clnt_hdl);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
ep = &ipa3_ctx->ep[clnt_hdl];
|
||||
|
||||
while (cnt < weight &&
|
||||
atomic_read(&ep->sys->curr_polling_state)) {
|
||||
|
||||
if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
|
||||
ret = ipa_poll_gsi_pkt(ep->sys, &mem_info);
|
||||
else
|
||||
ret = ipa_poll_sps_pkt(ep->sys, &mem_info);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
ipa3_wq_rx_common(ep->sys, mem_info.size);
|
||||
cnt += 5;
|
||||
};
|
||||
|
||||
if (cnt == 0) {
|
||||
ep->inactive_cycles++;
|
||||
ep->client_notify(ep->priv, IPA_CLIENT_COMP_NAPI, 0);
|
||||
|
||||
if (ep->inactive_cycles > 3 || ep->sys->len == 0) {
|
||||
ep->switch_to_intr = true;
|
||||
delay = 0;
|
||||
}
|
||||
queue_delayed_work(ep->sys->wq,
|
||||
&ep->sys->switch_to_intr_work, msecs_to_jiffies(delay));
|
||||
} else
|
||||
ep->inactive_cycles = 0;
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static unsigned long tag_to_pointer_wa(uint64_t tag)
|
||||
{
|
||||
return 0xFFFF000000000000 | (unsigned long) tag;
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
#define MTU_BYTE 1500
|
||||
|
||||
#define IPA3_MAX_NUM_PIPES 31
|
||||
#define IPA_WAN_CONS_DESC_FIFO_SZ 0x5E80
|
||||
#define IPA_WAN_NAPI_CONS_RX_POOL_SZ 3000
|
||||
#define IPA_SYS_DESC_FIFO_SZ 0x800
|
||||
#define IPA_SYS_TX_DATA_DESC_FIFO_SZ 0x1000
|
||||
#define IPA_LAN_RX_HEADER_LENGTH (2)
|
||||
|
@ -550,6 +552,7 @@ struct ipa3_status_stats {
|
|||
* @disconnect_in_progress: Indicates client disconnect in progress.
|
||||
* @qmi_request_sent: Indicates whether QMI request to enable clear data path
|
||||
* request is sent or not.
|
||||
* @napi_enabled: when true, IPA call client callback to start polling
|
||||
*/
|
||||
struct ipa3_ep_context {
|
||||
int valid;
|
||||
|
@ -586,6 +589,10 @@ struct ipa3_ep_context {
|
|||
u32 wdi_state;
|
||||
bool disconnect_in_progress;
|
||||
u32 qmi_request_sent;
|
||||
bool napi_enabled;
|
||||
bool switch_to_intr;
|
||||
int inactive_cycles;
|
||||
u32 eot_in_poll_err;
|
||||
|
||||
/* sys MUST be the last element of this struct */
|
||||
struct ipa3_sys_context *sys;
|
||||
|
@ -2262,4 +2269,6 @@ int ipa3_load_fws(const struct firmware *firmware);
|
|||
int ipa3_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data);
|
||||
const char *ipa_hw_error_str(enum ipa3_hw_errors err_type);
|
||||
int ipa_gsi_ch20_wa(void);
|
||||
int ipa3_rx_poll(u32 clnt_hdl, int budget);
|
||||
void ipa3_recycle_wan_skb(struct sk_buff *skb);
|
||||
#endif /* _IPA3_I_H_ */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2015-2016, 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
|
||||
|
@ -127,6 +127,24 @@ TRACE_EVENT(
|
|||
TP_printk("rx_pkt_cnt=%lu", __entry->rx_pkt_cnt)
|
||||
);
|
||||
|
||||
TRACE_EVENT(
|
||||
rmnet_ipa_netif_rcv_skb3,
|
||||
|
||||
TP_PROTO(unsigned long rx_pkt_cnt),
|
||||
|
||||
TP_ARGS(rx_pkt_cnt),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned long, rx_pkt_cnt)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->rx_pkt_cnt = rx_pkt_cnt;
|
||||
),
|
||||
|
||||
TP_printk("rx_pkt_cnt=%lu", __entry->rx_pkt_cnt)
|
||||
);
|
||||
|
||||
#endif /* _IPA_TRACE_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
|
|
@ -4657,6 +4657,8 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
|
|||
ipa3_set_required_perf_profile;
|
||||
api_ctrl->ipa_get_ipc_logbuf = ipa3_get_ipc_logbuf;
|
||||
api_ctrl->ipa_get_ipc_logbuf_low = ipa3_get_ipc_logbuf_low;
|
||||
api_ctrl->ipa_rx_poll = ipa3_rx_poll;
|
||||
api_ctrl->ipa_recycle_wan_skb = ipa3_recycle_wan_skb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#define IPA_QUOTA_REACH_ALERT_MAX_SIZE 64
|
||||
#define IPA_QUOTA_REACH_IF_NAME_MAX_SIZE 64
|
||||
#define IPA_UEVENT_NUM_EVNP 4 /* number of event pointers */
|
||||
#define NAPI_WEIGHT 60
|
||||
|
||||
#define IPA_NETDEV() \
|
||||
((rmnet_ipa3_ctx && rmnet_ipa3_ctx->wwan_priv) ? \
|
||||
|
@ -66,6 +67,8 @@
|
|||
static int ipa3_wwan_add_ul_flt_rule_to_ipa(void);
|
||||
static int ipa3_wwan_del_ul_flt_rule_to_ipa(void);
|
||||
static void ipa3_wwan_msg_free_cb(void*, u32, u32);
|
||||
static void ipa3_rmnet_rx_cb(void *priv);
|
||||
static int ipa3_rmnet_poll(struct napi_struct *napi, int budget);
|
||||
|
||||
static void ipa3_wake_tx_queue(struct work_struct *work);
|
||||
static DECLARE_WORK(ipa3_tx_wakequeue_work, ipa3_wake_tx_queue);
|
||||
|
@ -83,6 +86,7 @@ struct ipa3_rmnet_plat_drv_res {
|
|||
bool ipa_rmnet_ssr;
|
||||
bool ipa_loaduC;
|
||||
bool ipa_advertise_sg_support;
|
||||
bool ipa_napi_enable;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -109,6 +113,7 @@ struct ipa3_wwan_private {
|
|||
spinlock_t lock;
|
||||
struct completion resource_granted_completion;
|
||||
enum ipa3_wwan_device_status device_status;
|
||||
struct napi_struct napi;
|
||||
};
|
||||
|
||||
struct rmnet_ipa3_context {
|
||||
|
@ -134,6 +139,7 @@ struct rmnet_ipa3_context {
|
|||
};
|
||||
|
||||
static struct rmnet_ipa3_context *rmnet_ipa3_ctx;
|
||||
static struct ipa3_rmnet_plat_drv_res ipa3_rmnet_res;
|
||||
|
||||
/**
|
||||
* ipa3_setup_a7_qmap_hdr() - Setup default a7 qmap hdr
|
||||
|
@ -957,6 +963,9 @@ static int __ipa_wwan_open(struct net_device *dev)
|
|||
if (wwan_ptr->device_status != WWAN_DEVICE_ACTIVE)
|
||||
reinit_completion(&wwan_ptr->resource_granted_completion);
|
||||
wwan_ptr->device_status = WWAN_DEVICE_ACTIVE;
|
||||
|
||||
if (ipa3_rmnet_res.ipa_napi_enable)
|
||||
napi_enable(&(wwan_ptr->napi));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1189,39 +1198,47 @@ static void apps_ipa_packet_receive_notify(void *priv,
|
|||
enum ipa_dp_evt_type evt,
|
||||
unsigned long data)
|
||||
{
|
||||
struct sk_buff *skb = (struct sk_buff *)data;
|
||||
struct net_device *dev = (struct net_device *)priv;
|
||||
int result;
|
||||
unsigned int packet_len = skb->len;
|
||||
|
||||
IPAWANDBG_LOW("Rx packet was received");
|
||||
if (evt != IPA_RECEIVE) {
|
||||
IPAWANERR("A none IPA_RECEIVE event in wan_ipa_receive\n");
|
||||
return;
|
||||
}
|
||||
if (evt == IPA_RECEIVE) {
|
||||
struct sk_buff *skb = (struct sk_buff *)data;
|
||||
int result;
|
||||
unsigned int packet_len = skb->len;
|
||||
|
||||
skb->dev = IPA_NETDEV();
|
||||
skb->protocol = htons(ETH_P_MAP);
|
||||
IPAWANDBG_LOW("Rx packet was received");
|
||||
skb->dev = IPA_NETDEV();
|
||||
skb->protocol = htons(ETH_P_MAP);
|
||||
|
||||
if (dev->stats.rx_packets % IPA_WWAN_RX_SOFTIRQ_THRESH == 0) {
|
||||
trace_rmnet_ipa_netifni3(dev->stats.rx_packets);
|
||||
result = netif_rx_ni(skb);
|
||||
} else {
|
||||
trace_rmnet_ipa_netifrx3(dev->stats.rx_packets);
|
||||
result = netif_rx(skb);
|
||||
}
|
||||
if (ipa3_rmnet_res.ipa_napi_enable) {
|
||||
trace_rmnet_ipa_netif_rcv_skb3(dev->stats.rx_packets);
|
||||
result = netif_receive_skb(skb);
|
||||
} else {
|
||||
if (dev->stats.rx_packets % IPA_WWAN_RX_SOFTIRQ_THRESH
|
||||
== 0) {
|
||||
trace_rmnet_ipa_netifni3(dev->stats.rx_packets);
|
||||
result = netif_rx_ni(skb);
|
||||
} else {
|
||||
trace_rmnet_ipa_netifrx3(dev->stats.rx_packets);
|
||||
result = netif_rx(skb);
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
pr_err_ratelimited(DEV_NAME " %s:%d fail on netif_rx\n",
|
||||
__func__, __LINE__);
|
||||
dev->stats.rx_dropped++;
|
||||
}
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += packet_len;
|
||||
if (result) {
|
||||
pr_err_ratelimited(DEV_NAME " %s:%d fail on netif_receive_skb\n",
|
||||
__func__, __LINE__);
|
||||
dev->stats.rx_dropped++;
|
||||
}
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += packet_len;
|
||||
} else if (evt == IPA_CLIENT_START_POLL)
|
||||
ipa3_rmnet_rx_cb(priv);
|
||||
else if (evt == IPA_CLIENT_COMP_NAPI) {
|
||||
if (ipa3_rmnet_res.ipa_napi_enable)
|
||||
napi_complete(&(rmnet_ipa3_ctx->wwan_priv->napi));
|
||||
} else
|
||||
IPAWANERR("Invalid evt %d received in wan_ipa_receive\n", evt);
|
||||
}
|
||||
|
||||
static struct ipa3_rmnet_plat_drv_res ipa3_rmnet_res = {0, };
|
||||
|
||||
/**
|
||||
* ipa3_wwan_ioctl() - I/O control for wwan network driver.
|
||||
*
|
||||
|
@ -1595,10 +1612,17 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
IPA_CLIENT_APPS_WAN_CONS;
|
||||
rmnet_ipa3_ctx->ipa_to_apps_ep_cfg.notify =
|
||||
apps_ipa_packet_receive_notify;
|
||||
rmnet_ipa3_ctx->ipa_to_apps_ep_cfg.desc_fifo_sz =
|
||||
IPA_SYS_DESC_FIFO_SZ;
|
||||
rmnet_ipa3_ctx->ipa_to_apps_ep_cfg.priv = dev;
|
||||
|
||||
rmnet_ipa3_ctx->ipa_to_apps_ep_cfg.napi_enabled =
|
||||
ipa3_rmnet_res.ipa_napi_enable;
|
||||
if (rmnet_ipa3_ctx->ipa_to_apps_ep_cfg.napi_enabled)
|
||||
rmnet_ipa3_ctx->ipa_to_apps_ep_cfg.
|
||||
desc_fifo_sz = IPA_WAN_CONS_DESC_FIFO_SZ;
|
||||
else
|
||||
rmnet_ipa3_ctx->ipa_to_apps_ep_cfg.
|
||||
desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
|
||||
|
||||
mutex_lock(
|
||||
&rmnet_ipa3_ctx->ipa_to_apps_pipe_handle_guard);
|
||||
if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
|
||||
|
@ -2126,6 +2150,9 @@ static int ipa3_wwan_probe(struct platform_device *pdev)
|
|||
if (ipa3_rmnet_res.ipa_advertise_sg_support)
|
||||
dev->hw_features |= NETIF_F_SG;
|
||||
|
||||
if (ipa3_rmnet_res.ipa_napi_enable)
|
||||
netif_napi_add(dev, &(rmnet_ipa3_ctx->wwan_priv->napi),
|
||||
ipa3_rmnet_poll, NAPI_WEIGHT);
|
||||
ret = register_netdev(dev);
|
||||
if (ret) {
|
||||
IPAWANERR("unable to register ipa_netdev %d rc=%d\n",
|
||||
|
@ -2149,6 +2176,8 @@ static int ipa3_wwan_probe(struct platform_device *pdev)
|
|||
pr_info("rmnet_ipa completed initialization\n");
|
||||
return 0;
|
||||
config_err:
|
||||
if (ipa3_rmnet_res.ipa_napi_enable)
|
||||
netif_napi_del(&(rmnet_ipa3_ctx->wwan_priv->napi));
|
||||
unregister_netdev(dev);
|
||||
set_perf_err:
|
||||
ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
|
||||
|
@ -2196,6 +2225,8 @@ static int ipa3_wwan_remove(struct platform_device *pdev)
|
|||
IPAWANERR("Failed to teardown IPA->APPS pipe\n");
|
||||
else
|
||||
rmnet_ipa3_ctx->ipa3_to_apps_hdl = -1;
|
||||
if (ipa3_rmnet_res.ipa_napi_enable)
|
||||
netif_napi_del(&(rmnet_ipa3_ctx->wwan_priv->napi));
|
||||
mutex_unlock(&rmnet_ipa3_ctx->ipa_to_apps_pipe_handle_guard);
|
||||
unregister_netdev(IPA_NETDEV());
|
||||
ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
|
||||
|
@ -2903,6 +2934,22 @@ static void ipa3_wwan_msg_free_cb(void *buff, u32 len, u32 type)
|
|||
kfree(buff);
|
||||
}
|
||||
|
||||
static void ipa3_rmnet_rx_cb(void *priv)
|
||||
{
|
||||
IPAWANDBG_LOW("\n");
|
||||
napi_schedule(&(rmnet_ipa3_ctx->wwan_priv->napi));
|
||||
}
|
||||
|
||||
static int ipa3_rmnet_poll(struct napi_struct *napi, int budget)
|
||||
{
|
||||
int rcvd_pkts = 0;
|
||||
|
||||
rcvd_pkts = ipa_rx_poll(rmnet_ipa3_ctx->ipa3_to_apps_hdl,
|
||||
NAPI_WEIGHT);
|
||||
IPAWANDBG_LOW("rcvd packets: %d\n", rcvd_pkts);
|
||||
return rcvd_pkts;
|
||||
}
|
||||
|
||||
late_initcall(ipa3_wwan_init);
|
||||
module_exit(ipa3_wwan_cleanup);
|
||||
MODULE_DESCRIPTION("WWAN Network Interface");
|
||||
|
|
|
@ -93,6 +93,8 @@ enum ipa_aggr_mode {
|
|||
enum ipa_dp_evt_type {
|
||||
IPA_RECEIVE,
|
||||
IPA_WRITE_DONE,
|
||||
IPA_CLIENT_START_POLL,
|
||||
IPA_CLIENT_COMP_NAPI,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -538,6 +540,7 @@ struct ipa_ext_intf {
|
|||
* @skip_ep_cfg: boolean field that determines if EP should be configured
|
||||
* by IPA driver
|
||||
* @keep_ipa_awake: when true, IPA will not be clock gated
|
||||
* @napi_enabled: when true, IPA call client callback to start polling
|
||||
*/
|
||||
struct ipa_sys_connect_params {
|
||||
struct ipa_ep_cfg ipa_ep_cfg;
|
||||
|
@ -547,6 +550,7 @@ struct ipa_sys_connect_params {
|
|||
ipa_notify_cb notify;
|
||||
bool skip_ep_cfg;
|
||||
bool keep_ipa_awake;
|
||||
bool napi_enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1233,6 +1237,8 @@ int ipa_tx_dp_mul(enum ipa_client_type dst,
|
|||
struct ipa_tx_data_desc *data_desc);
|
||||
|
||||
void ipa_free_skb(struct ipa_rx_data *);
|
||||
int ipa_rx_poll(u32 clnt_hdl, int budget);
|
||||
void ipa_recycle_wan_skb(struct sk_buff *skb);
|
||||
|
||||
/*
|
||||
* System pipes
|
||||
|
@ -1763,6 +1769,15 @@ static inline void ipa_free_skb(struct ipa_rx_data *rx_in)
|
|||
return;
|
||||
}
|
||||
|
||||
static inline int ipa_rx_poll(u32 clnt_hdl, int budget)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static inline void ipa_recycle_wan_skb(struct sk_buff *skb)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* System pipes
|
||||
*/
|
||||
|
|
Loading…
Add table
Reference in a new issue