msm: ipa: support qmap control pkt using pkt_init

Currently the qmap control pkts are sent back to AP
from modem because of exception. The fix is
to use pkt_init to skip filtering/natting on IPA-HW to
reach modem instead. Also there is a requirement for
AP-side to send back qmap flow control acks immediately
after receiving the requets. The code change is to make
2st level high-watermark for those qmap control pkts to
not be dropped. Also rmnet_ipa driver won't stop queue
if the current pkt is qmap control pkt even when
outstanding pkts above the first level of
high-watermark.

Change-Id: I3074e4a37d74c491593e109c1df0c99da85a5e57
Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
This commit is contained in:
Skylar Chang 2016-02-05 16:05:35 -08:00 committed by David Keitel
parent c28a277ec8
commit f912da63c5
2 changed files with 96 additions and 41 deletions

View file

@ -33,6 +33,7 @@
#include "ipa_qmi_service.h"
#include <linux/rmnet_ipa_fd_ioctl.h>
#include <linux/ipa.h>
#include <uapi/linux/net_map.h>
#include "ipa_trace.h"
@ -44,6 +45,7 @@
#define TAILROOM 0 /* for padding by mux layer */
#define MAX_NUM_OF_MUX_CHANNEL 10 /* max mux channels */
#define UL_FILTER_RULE_HANDLE_START 69
#define DEFAULT_OUTSTANDING_HIGH_CTL 96
#define DEFAULT_OUTSTANDING_HIGH 64
#define DEFAULT_OUTSTANDING_LOW 32
@ -110,6 +112,7 @@ struct wwan_private {
struct net_device *net;
struct net_device_stats stats;
atomic_t outstanding_pkts;
int outstanding_high_ctl;
int outstanding_high;
int outstanding_low;
uint32_t ch_id;
@ -1023,12 +1026,45 @@ static int ipa_wwan_change_mtu(struct net_device *dev, int new_mtu)
static int ipa_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
{
int ret = 0;
bool qmap_check;
struct wwan_private *wwan_ptr = netdev_priv(dev);
struct ipa_tx_meta meta;
if (netif_queue_stopped(dev)) {
IPAWANERR("[%s]fatal: ipa_wwan_xmit stopped\n", dev->name);
return 0;
if (skb->protocol != htons(ETH_P_MAP)) {
IPAWANDBG
("SW filtering out none QMAP packet received from %s",
current->comm);
return NETDEV_TX_OK;
}
qmap_check = RMNET_MAP_GET_CD_BIT(skb);
if (netif_queue_stopped(dev)) {
if (qmap_check &&
atomic_read(&wwan_ptr->outstanding_pkts) <
wwan_ptr->outstanding_high_ctl) {
pr_err("[%s]Queue stop, send ctrl pkts\n", dev->name);
goto send;
} else {
pr_err("[%s]fatal: ipa_wwan_xmit stopped\n", dev->name);
return NETDEV_TX_BUSY;
}
}
/* checking High WM hit */
if (atomic_read(&wwan_ptr->outstanding_pkts) >=
wwan_ptr->outstanding_high) {
if (!qmap_check) {
IPAWANDBG("pending(%d)/(%d)- stop(%d), qmap_chk(%d)\n",
atomic_read(&wwan_ptr->outstanding_pkts),
wwan_ptr->outstanding_high,
netif_queue_stopped(dev),
qmap_check);
netif_stop_queue(dev);
return NETDEV_TX_BUSY;
}
}
send:
/* IPA_RM checking start */
ret = ipa2_rm_inactivity_timer_request_resource(
IPA_RM_RESOURCE_WWAN_0_PROD);
@ -1042,24 +1078,16 @@ static int ipa_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
return -EFAULT;
}
/* IPA_RM checking end */
if (skb->protocol != htons(ETH_P_MAP)) {
IPAWANDBG
("SW filtering out none QMAP packet received from %s",
current->comm);
ret = NETDEV_TX_OK;
goto out;
if (qmap_check) {
memset(&meta, 0, sizeof(meta));
meta.pkt_init_dst_ep_valid = true;
meta.pkt_init_dst_ep_remote = true;
ret = ipa2_tx_dp(IPA_CLIENT_Q6_LAN_CONS, skb, &meta);
} else {
ret = ipa2_tx_dp(IPA_CLIENT_APPS_LAN_WAN_PROD, skb, NULL);
}
/* checking High WM hit */
if (atomic_read(&wwan_ptr->outstanding_pkts) >=
wwan_ptr->outstanding_high) {
IPAWANDBG("Outstanding high (%d)- stopping\n",
wwan_ptr->outstanding_high);
netif_stop_queue(dev);
ret = NETDEV_TX_BUSY;
goto out;
}
ret = ipa2_tx_dp(IPA_CLIENT_APPS_LAN_WAN_PROD, skb, NULL);
if (ret) {
ret = NETDEV_TX_BUSY;
dev->stats.tx_dropped++;
@ -1070,7 +1098,6 @@ static int ipa_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
ret = NETDEV_TX_OK;
out:
ipa2_rm_inactivity_timer_release_resource(
IPA_RM_RESOURCE_WWAN_0_PROD);
@ -1118,7 +1145,7 @@ static void apps_ipa_tx_complete_notify(void *priv,
netif_queue_stopped(wwan_ptr->net) &&
atomic_read(&wwan_ptr->outstanding_pkts) <
(wwan_ptr->outstanding_low)) {
IPAWANDBG("Outstanding low (%d) - waking up queue\n",
IPAWANDBG("Outstanding low (%d) - wake up queue\n",
wwan_ptr->outstanding_low);
netif_wake_queue(wwan_ptr->net);
}
@ -1965,6 +1992,7 @@ static int ipa_wwan_probe(struct platform_device *pdev)
memset(wwan_ptr, 0, sizeof(*wwan_ptr));
IPAWANDBG("wwan_ptr (private) = %p", wwan_ptr);
wwan_ptr->net = dev;
wwan_ptr->outstanding_high_ctl = DEFAULT_OUTSTANDING_HIGH_CTL;
wwan_ptr->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
wwan_ptr->outstanding_low = DEFAULT_OUTSTANDING_LOW;
atomic_set(&wwan_ptr->outstanding_pkts, 0);

View file

@ -33,6 +33,7 @@
#include "ipa_qmi_service.h"
#include <linux/rmnet_ipa_fd_ioctl.h>
#include <linux/ipa.h>
#include <uapi/linux/net_map.h>
#include "ipa_trace.h"
@ -44,6 +45,7 @@
#define TAILROOM 0 /* for padding by mux layer */
#define MAX_NUM_OF_MUX_CHANNEL 10 /* max mux channels */
#define UL_FILTER_RULE_HANDLE_START 69
#define DEFAULT_OUTSTANDING_HIGH_CTL 96
#define DEFAULT_OUTSTANDING_HIGH 64
#define DEFAULT_OUTSTANDING_LOW 32
@ -99,6 +101,7 @@ struct ipa3_wwan_private {
struct net_device *net;
struct net_device_stats stats;
atomic_t outstanding_pkts;
int outstanding_high_ctl;
int outstanding_high;
int outstanding_low;
uint32_t ch_id;
@ -1043,12 +1046,45 @@ static int ipa3_wwan_change_mtu(struct net_device *dev, int new_mtu)
static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
{
int ret = 0;
bool qmap_check;
struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
struct ipa_tx_meta meta;
if (netif_queue_stopped(dev)) {
IPAWANERR("[%s]fatal: ipa3_wwan_xmit stopped\n", dev->name);
return 0;
if (skb->protocol != htons(ETH_P_MAP)) {
IPAWANDBG
("SW filtering out none QMAP packet received from %s",
current->comm);
return NETDEV_TX_OK;
}
qmap_check = RMNET_MAP_GET_CD_BIT(skb);
if (netif_queue_stopped(dev)) {
if (qmap_check &&
atomic_read(&wwan_ptr->outstanding_pkts) <
wwan_ptr->outstanding_high_ctl) {
pr_err("[%s]Queue stop, send ctrl pkts\n", dev->name);
goto send;
} else {
pr_err("[%s]fatal: ipa_wwan_xmit stopped\n", dev->name);
return NETDEV_TX_BUSY;
}
}
/* checking High WM hit */
if (atomic_read(&wwan_ptr->outstanding_pkts) >=
wwan_ptr->outstanding_high) {
if (!qmap_check) {
IPAWANDBG("pending(%d)/(%d)- stop(%d), qmap_chk(%d)\n",
atomic_read(&wwan_ptr->outstanding_pkts),
wwan_ptr->outstanding_high,
netif_queue_stopped(dev),
qmap_check);
netif_stop_queue(dev);
return NETDEV_TX_BUSY;
}
}
send:
/* IPA_RM checking start */
ret = ipa3_rm_inactivity_timer_request_resource(
IPA_RM_RESOURCE_WWAN_0_PROD);
@ -1062,24 +1098,16 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
return -EFAULT;
}
/* IPA_RM checking end */
if (skb->protocol != htons(ETH_P_MAP)) {
IPAWANDBG
("SW filtering out none QMAP packet received from %s",
current->comm);
ret = NETDEV_TX_OK;
goto out;
if (RMNET_MAP_GET_CD_BIT(skb)) {
memset(&meta, 0, sizeof(meta));
meta.pkt_init_dst_ep_valid = true;
meta.pkt_init_dst_ep_remote = true;
ret = ipa3_tx_dp(IPA_CLIENT_Q6_LAN_CONS, skb, &meta);
} else {
ret = ipa3_tx_dp(IPA_CLIENT_APPS_LAN_WAN_PROD, skb, NULL);
}
/* checking High WM hit */
if (atomic_read(&wwan_ptr->outstanding_pkts) >=
wwan_ptr->outstanding_high) {
IPAWANDBG("Outstanding high (%d)- stopping\n",
wwan_ptr->outstanding_high);
netif_stop_queue(dev);
ret = NETDEV_TX_BUSY;
goto out;
}
ret = ipa3_tx_dp(IPA_CLIENT_APPS_LAN_WAN_PROD, skb, NULL);
if (ret) {
ret = NETDEV_TX_BUSY;
dev->stats.tx_dropped++;
@ -1090,7 +1118,6 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
ret = NETDEV_TX_OK;
out:
ipa3_rm_inactivity_timer_release_resource(
IPA_RM_RESOURCE_WWAN_0_PROD);