qcacld-3.0: Support WDI 3.0 SW path intra-bss forwarding

Support WDI 3.0 SW path intra-bss forwarding. Major
difference for WDI 3.0 is the metadata info passed
from ipa driver in skb->cb[].

Previously intra-bss fwd decision is done by FW and
it passes fw_desc to IPA where IPA driver passes onto
WLAN driver. Now for WDI 3.0, FW is not involved in RX
path and SW path intra-bss fwd decision has to be done
in wlan driver.

Change-Id: I0b4b9bbf16440dd47b6f97460f8931ea3a79303c
CRs-Fixed: 2426857
This commit is contained in:
jiad 2019-03-25 15:22:42 +08:00 committed by nshrivas
parent a994c9aadb
commit 90b1725a4f

View File

@ -275,6 +275,115 @@ static void wlan_ipa_send_pkt_to_tl(
iface_context->stats.num_tx++;
}
/**
* wlan_ipa_forward() - handle packet forwarding to wlan tx
* @ipa_ctx: pointer to ipa ipa context
* @iface_ctx: interface context
* @skb: data pointer
*
* if exception packet has set forward bit, copied new packet should be
* forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
* put into pm queue and tx procedure will be differed
*
* Return: None
*/
static void wlan_ipa_forward(struct wlan_ipa_priv *ipa_ctx,
struct wlan_ipa_iface_context *iface_ctx,
qdf_nbuf_t skb)
{
struct wlan_ipa_pm_tx_cb *pm_tx_cb;
qdf_spin_lock_bh(&ipa_ctx->pm_lock);
/* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
qdf_nbuf_ipa_owned_set(skb);
/* WLAN subsystem is in suspend, put in queue */
if (ipa_ctx->suspended) {
qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
ipa_info_rl("Tx in suspend, put in queue");
qdf_mem_zero(skb->cb, sizeof(skb->cb));
pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
pm_tx_cb->exception = true;
pm_tx_cb->iface_context = iface_ctx;
qdf_spin_lock_bh(&ipa_ctx->pm_lock);
qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb);
qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
ipa_ctx->stats.num_tx_queued++;
} else {
/* Resume, put packet into WLAN TX */
qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
if (ipa_ctx->softap_xmit) {
if (ipa_ctx->softap_xmit(skb, iface_ctx->dev)) {
ipa_err_rl("packet Tx fail");
ipa_ctx->stats.num_tx_fwd_err++;
} else {
ipa_ctx->stats.num_tx_fwd_ok++;
}
} else {
dev_kfree_skb_any(skb);
}
}
}
/**
* wlan_ipa_intrabss_forward() - Forward intra bss packets.
* @ipa_ctx: pointer to IPA IPA struct
* @iface_ctx: ipa interface context
* @desc: Firmware descriptor
* @skb: Data buffer
*
* Return:
* WLAN_IPA_FORWARD_PKT_NONE
* WLAN_IPA_FORWARD_PKT_DISCARD
* WLAN_IPA_FORWARD_PKT_LOCAL_STACK
*
*/
static enum wlan_ipa_forward_type wlan_ipa_intrabss_forward(
struct wlan_ipa_priv *ipa_ctx,
struct wlan_ipa_iface_context *iface_ctx,
uint8_t desc,
qdf_nbuf_t skb)
{
int ret = WLAN_IPA_FORWARD_PKT_NONE;
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
if ((desc & FW_RX_DESC_FORWARD_M)) {
void *vdev = cdp_get_vdev_from_vdev_id(soc, pdev,
iface_ctx->session_id);
if (cdp_tx_desc_thresh_reached(soc, vdev)) {
/* Drop the packet*/
ipa_ctx->stats.num_tx_fwd_err++;
dev_kfree_skb_any(skb);
ret = WLAN_IPA_FORWARD_PKT_DISCARD;
return ret;
}
ipa_debug_rl("Forward packet to Tx (fw_desc=%d)", desc);
ipa_ctx->ipa_tx_forward++;
if ((desc & FW_RX_DESC_DISCARD_M)) {
wlan_ipa_forward(ipa_ctx, iface_ctx, skb);
ipa_ctx->ipa_rx_internal_drop_count++;
ipa_ctx->ipa_rx_discard++;
ret = WLAN_IPA_FORWARD_PKT_DISCARD;
} else {
struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
if (cloned_skb)
wlan_ipa_forward(ipa_ctx, iface_ctx,
cloned_skb);
else
ipa_err_rl("tx skb alloc failed");
ret = WLAN_IPA_FORWARD_PKT_LOCAL_STACK;
}
}
return ret;
}
#ifdef CONFIG_IPA_WDI_UNIFIED_API
/*
* TODO: Get WDI version through FW capabilities
@ -474,6 +583,40 @@ int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr)
return qdf_ipa_wdi_release_smmu_mapping(num_buf, buf_arr);
}
static enum wlan_ipa_forward_type
wlan_ipa_rx_intrabss_fwd(struct wlan_ipa_priv *ipa_ctx,
struct wlan_ipa_iface_context *iface_ctx,
qdf_nbuf_t nbuf)
{
uint8_t fw_desc = 0;
bool fwd_success;
int ret;
/* legacy intra-bss fowarding for WDI 1.0 and 2.0 */
if (ipa_ctx->wdi_version != IPA_WDI_3) {
fw_desc = (uint8_t)nbuf->cb[1];
return wlan_ipa_intrabss_forward(ipa_ctx, iface_ctx, fw_desc,
nbuf);
}
if (cdp_ipa_rx_intrabss_fwd(ipa_ctx->dp_soc, iface_ctx->tl_context,
nbuf, &fwd_success)) {
ipa_ctx->ipa_rx_internal_drop_count++;
ipa_ctx->ipa_rx_discard++;
ret = WLAN_IPA_FORWARD_PKT_DISCARD;
} else {
ret = WLAN_IPA_FORWARD_PKT_LOCAL_STACK;
}
if (fwd_success)
ipa_ctx->stats.num_tx_fwd_ok++;
else
ipa_ctx->stats.num_tx_fwd_err++;
return ret;
}
#else /* CONFIG_IPA_WDI_UNIFIED_API */
static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx)
@ -608,6 +751,18 @@ int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr)
return qdf_ipa_release_wdi_mapping(num_buf, buf_arr);
}
static enum wlan_ipa_forward_type
wlan_ipa_rx_intrabss_fwd(struct wlan_ipa_priv *ipa_ctx,
struct wlan_ipa_iface_context *iface_ctx,
qdf_nbuf_t nbuf)
{
uint8_t fw_desc;
fw_desc = (uint8_t)nbuf->cb[1];
return wlan_ipa_intrabss_forward(ipa_ctx, iface_ctx, fw_desc, nbuf);
}
#endif /* CONFIG_IPA_WDI_UNIFIED_API */
/**
@ -641,115 +796,6 @@ wlan_ipa_send_skb_to_network(qdf_nbuf_t skb,
ipa_ctx->ipa_rx_net_send_count++;
}
/**
* wlan_ipa_forward() - handle packet forwarding to wlan tx
* @ipa_ctx: pointer to ipa ipa context
* @iface_ctx: interface context
* @skb: data pointer
*
* if exception packet has set forward bit, copied new packet should be
* forwarded to wlan tx. if wlan subsystem is in suspend state, packet should
* put into pm queue and tx procedure will be differed
*
* Return: None
*/
static void wlan_ipa_forward(struct wlan_ipa_priv *ipa_ctx,
struct wlan_ipa_iface_context *iface_ctx,
qdf_nbuf_t skb)
{
struct wlan_ipa_pm_tx_cb *pm_tx_cb;
qdf_spin_lock_bh(&ipa_ctx->pm_lock);
/* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */
qdf_nbuf_ipa_owned_set(skb);
/* WLAN subsystem is in suspend, put in queue */
if (ipa_ctx->suspended) {
qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
ipa_info_rl("Tx in suspend, put in queue");
qdf_mem_zero(skb->cb, sizeof(skb->cb));
pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
pm_tx_cb->exception = true;
pm_tx_cb->iface_context = iface_ctx;
qdf_spin_lock_bh(&ipa_ctx->pm_lock);
qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb);
qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
ipa_ctx->stats.num_tx_queued++;
} else {
/* Resume, put packet into WLAN TX */
qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
if (ipa_ctx->softap_xmit) {
if (ipa_ctx->softap_xmit(skb, iface_ctx->dev)) {
ipa_err_rl("packet Tx fail");
ipa_ctx->stats.num_tx_fwd_err++;
} else {
ipa_ctx->stats.num_tx_fwd_ok++;
}
} else {
dev_kfree_skb_any(skb);
}
}
}
/**
* wlan_ipa_intrabss_forward() - Forward intra bss packets.
* @ipa_ctx: pointer to IPA IPA struct
* @iface_ctx: ipa interface context
* @desc: Firmware descriptor
* @skb: Data buffer
*
* Return:
* WLAN_IPA_FORWARD_PKT_NONE
* WLAN_IPA_FORWARD_PKT_DISCARD
* WLAN_IPA_FORWARD_PKT_LOCAL_STACK
*
*/
static enum wlan_ipa_forward_type wlan_ipa_intrabss_forward(
struct wlan_ipa_priv *ipa_ctx,
struct wlan_ipa_iface_context *iface_ctx,
uint8_t desc,
qdf_nbuf_t skb)
{
int ret = WLAN_IPA_FORWARD_PKT_NONE;
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
if ((desc & FW_RX_DESC_FORWARD_M)) {
void *vdev = cdp_get_vdev_from_vdev_id(soc, pdev,
iface_ctx->session_id);
if (cdp_tx_desc_thresh_reached(soc, vdev)) {
/* Drop the packet*/
ipa_ctx->stats.num_tx_fwd_err++;
dev_kfree_skb_any(skb);
ret = WLAN_IPA_FORWARD_PKT_DISCARD;
return ret;
}
ipa_debug_rl("Forward packet to Tx (fw_desc=%d)", desc);
ipa_ctx->ipa_tx_forward++;
if ((desc & FW_RX_DESC_DISCARD_M)) {
wlan_ipa_forward(ipa_ctx, iface_ctx, skb);
ipa_ctx->ipa_rx_internal_drop_count++;
ipa_ctx->ipa_rx_discard++;
ret = WLAN_IPA_FORWARD_PKT_DISCARD;
} else {
struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC);
if (cloned_skb)
wlan_ipa_forward(ipa_ctx, iface_ctx,
cloned_skb);
else
ipa_err_rl("tx skb alloc failed");
ret = WLAN_IPA_FORWARD_PKT_LOCAL_STACK;
}
}
return ret;
}
/**
* __wlan_ipa_w2i_cb() - WLAN to IPA callback handler
* @priv: pointer to private data registered with IPA (we register a
@ -767,7 +813,6 @@ static void __wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
uint8_t iface_id;
uint8_t session_id = 0xff;
struct wlan_ipa_iface_context *iface_context;
uint8_t fw_desc;
ipa_ctx = (struct wlan_ipa_priv *)priv;
if (!ipa_ctx) {
@ -827,10 +872,9 @@ static void __wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
* set, and forward to Tx. Then copy to kernel stack
* only when DISCARD bit is not set.
*/
fw_desc = (uint8_t)skb->cb[1];
if (WLAN_IPA_FORWARD_PKT_DISCARD ==
wlan_ipa_intrabss_forward(ipa_ctx, iface_context,
fw_desc, skb))
wlan_ipa_rx_intrabss_fwd(ipa_ctx, iface_context,
skb))
break;
} else {
ipa_debug_rl("Intra-BSS forwarding is disabled");