msm: ipa: add support to get tether stats

Wan-driver needs to get those new ioctls from
CNE and send QMI-msg to modem to get the ipa
tethering stats and update to android framework.

Change-Id: Iceea65bb3f20215967e7cbb04cf425b91aef24d4
Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
This commit is contained in:
Skylar Chang 2015-09-14 16:42:29 -07:00 committed by Gerrit - the friendly Code Review server
parent 0dcd2def74
commit 092e78db0e
6 changed files with 405 additions and 6 deletions

View file

@ -1062,6 +1062,16 @@ struct ipa_sps_pm {
atomic_t eot_activity;
};
/**
* struct ipacm_client_info - the client-info indicated from IPACM
* @ipacm_client_enum: the enum to indicate tether-client
* @ipacm_client_uplink: the bool to indicate pipe for uplink
*/
struct ipacm_client_info {
enum ipacm_client_enum client_enum;
bool uplink;
};
/**
* struct ipa_context - IPA context
* @class: pointer to the struct class
@ -1241,6 +1251,8 @@ struct ipa_context {
/* RMNET_IOCTL_INGRESS_FORMAT_AGG_DATA */
bool ipa_client_apps_wan_cons_agg_gro;
bool tethered_flow_control;
/* M-release support to know client pipes */
struct ipacm_client_info ipacm_client[IPA_MAX_NUM_PIPES];
};
/**
@ -1403,6 +1415,15 @@ struct ipa_controller {
extern struct ipa_context *ipa_ctx;
/*
* Tethering client info
*/
void ipa_set_client(int index, enum ipacm_client_enum client, bool uplink);
enum ipacm_client_enum ipa_get_client(int pipe_idx);
bool ipa_get_client_uplink(int pipe_idx);
int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
bool in_atomic);
int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,

View file

@ -61,6 +61,10 @@ struct rmnet_mux_val {
int rmnet_ipa_poll_tethering_stats(struct wan_ioctl_poll_tethering_stats *data);
int rmnet_ipa_set_data_quota(struct wan_ioctl_set_data_quota *data);
void ipa_broadcast_quota_reach_ind(uint32_t mux_id);
int rmnet_ipa_set_tether_client_pipe(struct wan_ioctl_set_tether_client_pipe
*data);
int rmnet_ipa_query_tethering_stats(struct wan_ioctl_query_tether_stats *data,
bool reset);
int ipa_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req,
struct ipa_get_data_stats_resp_msg_v01 *resp);

View file

@ -907,6 +907,53 @@ int ipa_get_ep_mapping(enum ipa_client_type client)
}
EXPORT_SYMBOL(ipa_get_ep_mapping);
/* ipa_set_client() - provide client mapping
* @client: client type
*
* Return value: none
*/
void ipa_set_client(int index, enum ipacm_client_enum client, bool uplink)
{
if (client >= IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) {
IPAERR("Bad client number! client =%d\n", client);
} else if (index >= IPA_MAX_NUM_PIPES || index < 0) {
IPAERR("Bad pipe index! index =%d\n", index);
} else {
ipa_ctx->ipacm_client[index].client_enum = client;
ipa_ctx->ipacm_client[index].uplink = uplink;
}
}
EXPORT_SYMBOL(ipa_set_client);
/**
* ipa_get_client() - provide client mapping
* @client: client type
*
* Return value: none
*/
enum ipacm_client_enum ipa_get_client(int pipe_idx)
{
if (pipe_idx >= IPA_MAX_NUM_PIPES || pipe_idx < 0) {
IPAERR("Bad pipe index! pipe_idx =%d\n", pipe_idx);
return IPACM_CLIENT_MAX;
} else {
return ipa_ctx->ipacm_client[pipe_idx].client_enum;
}
}
EXPORT_SYMBOL(ipa_get_client);
/**
* ipa_get_client_uplink() - provide client mapping
* @client: client type
*
* Return value: none
*/
bool ipa_get_client_uplink(int pipe_idx)
{
return ipa_ctx->ipacm_client[pipe_idx].uplink;
}
EXPORT_SYMBOL(ipa_get_client_uplink);
/**
* ipa_get_rm_resource_from_ep() - get the IPA_RM resource which is related to
* the supplied pipe index.

View file

@ -52,6 +52,7 @@
#define INVALID_MUX_ID 0xFF
#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 */
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;
@ -2384,6 +2385,9 @@ int rmnet_ipa_set_data_quota(struct wan_ioctl_set_data_quota *data)
struct ipa_set_data_usage_quota_req_msg_v01 req;
index = find_vchannel_name_index(data->interface_name);
IPAWANERR("iface name %s, quota %lu\n",
data->interface_name,
(unsigned long int) data->quota_mbytes);
if (index == MAX_NUM_OF_MUX_CHANNEL) {
IPAWANERR("%s is an invalid iface name\n",
@ -2404,6 +2408,199 @@ int rmnet_ipa_set_data_quota(struct wan_ioctl_set_data_quota *data)
return ipa_qmi_set_data_quota(&req);
}
/* rmnet_ipa_set_tether_client_pipe() -
* @data - IOCTL data
*
* This function handles WAN_IOC_SET_DATA_QUOTA.
* It translates the given interface name to the Modem MUX ID and
* sends the request of the quota to the IPA Modem driver via QMI.
*
* Return codes:
* 0: Success
* -EFAULT: Invalid interface name provided
* other: See ipa_qmi_set_data_quota
*/
int rmnet_ipa_set_tether_client_pipe(
struct wan_ioctl_set_tether_client_pipe *data)
{
int number, i;
IPAWANDBG("client %d, UL %d, DL %d, reset %d\n",
data->ipa_client,
data->ul_src_pipe_len,
data->dl_dst_pipe_len,
data->reset_client);
number = data->ul_src_pipe_len;
for (i = 0; i < number; i++) {
IPAWANDBG("UL index-%d pipe %d\n", i,
data->ul_src_pipe_list[i]);
if (data->reset_client)
ipa_set_client(data->ul_src_pipe_list[i],
0, false);
else
ipa_set_client(data->ul_src_pipe_list[i],
data->ipa_client, true);
}
number = data->dl_dst_pipe_len;
for (i = 0; i < number; i++) {
IPAWANDBG("DL index-%d pipe %d\n", i,
data->dl_dst_pipe_list[i]);
if (data->reset_client)
ipa_set_client(data->dl_dst_pipe_list[i],
0, false);
else
ipa_set_client(data->dl_dst_pipe_list[i],
data->ipa_client, false);
}
return 0;
}
int rmnet_ipa_query_tethering_stats(struct wan_ioctl_query_tether_stats *data,
bool reset)
{
struct ipa_get_data_stats_req_msg_v01 *req;
struct ipa_get_data_stats_resp_msg_v01 *resp;
int pipe_len, rc;
req = kzalloc(sizeof(struct ipa_get_data_stats_req_msg_v01),
GFP_KERNEL);
if (!req) {
IPAWANERR("Can't allocate memory for stats message\n");
return rc;
}
resp = kzalloc(sizeof(struct ipa_get_data_stats_resp_msg_v01),
GFP_KERNEL);
if (!resp) {
IPAWANERR("Can't allocate memory for stats message\n");
kfree(req);
return rc;
}
memset(req, 0, sizeof(struct ipa_get_data_stats_req_msg_v01));
memset(resp, 0, sizeof(struct ipa_get_data_stats_resp_msg_v01));
req->ipa_stats_type = QMI_IPA_STATS_TYPE_PIPE_V01;
if (reset) {
req->reset_stats_valid = true;
req->reset_stats = true;
IPAWANERR("reset the pipe stats\n");
} else {
/* print tethered-client enum */
IPAWANDBG("Tethered-client enum(%d)\n", data->ipa_client);
}
rc = ipa_qmi_get_data_stats(req, resp);
if (rc) {
IPAWANERR("can't get ipa_qmi_get_data_stats\n");
kfree(req);
kfree(resp);
return rc;
} else if (reset) {
kfree(req);
kfree(resp);
return 0;
}
if (resp->dl_dst_pipe_stats_list_valid) {
for (pipe_len = 0; pipe_len < resp->dl_dst_pipe_stats_list_len;
pipe_len++) {
IPAWANDBG("Check entry(%d) dl_dst_pipe(%d)\n",
pipe_len, resp->dl_dst_pipe_stats_list
[pipe_len].pipe_index);
IPAWANDBG("dl_p_v4(%lu)v6(%lu) dl_b_v4(%lu)v6(%lu)\n",
(unsigned long int) resp->
dl_dst_pipe_stats_list[pipe_len].
num_ipv4_packets,
(unsigned long int) resp->
dl_dst_pipe_stats_list[pipe_len].
num_ipv6_packets,
(unsigned long int) resp->
dl_dst_pipe_stats_list[pipe_len].
num_ipv4_bytes,
(unsigned long int) resp->
dl_dst_pipe_stats_list[pipe_len].
num_ipv6_bytes);
if (ipa_get_client_uplink(resp->
dl_dst_pipe_stats_list[pipe_len].
pipe_index) == false) {
if (data->ipa_client == ipa_get_client(resp->
dl_dst_pipe_stats_list[pipe_len].
pipe_index)) {
/* update the DL stats */
data->ipv4_rx_packets += resp->
dl_dst_pipe_stats_list[pipe_len].
num_ipv4_packets;
data->ipv6_rx_packets += resp->
dl_dst_pipe_stats_list[pipe_len].
num_ipv6_packets;
data->ipv4_rx_bytes += resp->
dl_dst_pipe_stats_list[pipe_len].
num_ipv4_bytes;
data->ipv6_rx_bytes += resp->
dl_dst_pipe_stats_list[pipe_len].
num_ipv6_bytes;
}
}
}
}
IPAWANDBG("v4_rx_p(%lu) v6_rx_p(%lu) v4_rx_b(%lu) v6_rx_b(%lu)\n",
(unsigned long int) data->ipv4_rx_packets,
(unsigned long int) data->ipv6_rx_packets,
(unsigned long int) data->ipv4_rx_bytes,
(unsigned long int) data->ipv6_rx_bytes);
if (resp->ul_src_pipe_stats_list_valid) {
for (pipe_len = 0; pipe_len < resp->ul_src_pipe_stats_list_len;
pipe_len++) {
IPAWANDBG("Check entry(%d) ul_dst_pipe(%d)\n",
pipe_len,
resp->ul_src_pipe_stats_list[pipe_len].
pipe_index);
IPAWANDBG("ul_p_v4(%lu)v6(%lu)ul_b_v4(%lu)v6(%lu)\n",
(unsigned long int) resp->
ul_src_pipe_stats_list[pipe_len].
num_ipv4_packets,
(unsigned long int) resp->
ul_src_pipe_stats_list[pipe_len].
num_ipv6_packets,
(unsigned long int) resp->
ul_src_pipe_stats_list[pipe_len].
num_ipv4_bytes,
(unsigned long int) resp->
ul_src_pipe_stats_list[pipe_len].
num_ipv6_bytes);
if (ipa_get_client_uplink(resp->
ul_src_pipe_stats_list[pipe_len].
pipe_index) == true) {
if (data->ipa_client == ipa_get_client(resp->
ul_src_pipe_stats_list[pipe_len].
pipe_index)) {
/* update the DL stats */
data->ipv4_tx_packets += resp->
ul_src_pipe_stats_list[pipe_len].
num_ipv4_packets;
data->ipv6_tx_packets += resp->
ul_src_pipe_stats_list[pipe_len].
num_ipv6_packets;
data->ipv4_tx_bytes += resp->
ul_src_pipe_stats_list[pipe_len].
num_ipv4_bytes;
data->ipv6_tx_bytes += resp->
ul_src_pipe_stats_list[pipe_len].
num_ipv6_bytes;
}
}
}
}
IPAWANDBG("tx_p_v4(%lu)v6(%lu)tx_b_v4(%lu) v6(%lu)\n",
(unsigned long int) data->ipv4_tx_packets,
(unsigned long int) data->ipv6_tx_packets,
(unsigned long int) data->ipv4_tx_bytes,
(unsigned long int) data->ipv6_tx_bytes);
kfree(req);
kfree(resp);
return 0;
}
/**
* ipa_broadcast_quota_reach_ind() - Send Netlink broadcast on Quota
* @mux_id - The MUX ID on which the quota has been reached
@ -2416,8 +2613,10 @@ int rmnet_ipa_set_data_quota(struct wan_ioctl_set_data_quota *data)
void ipa_broadcast_quota_reach_ind(u32 mux_id)
{
char alert_msg[IPA_QUOTA_REACH_ALERT_MAX_SIZE];
char iface_name[IPA_QUOTA_REACH_IF_NAME_MAX_SIZE];
char *envp[] = { alert_msg, iface_name, NULL };
char iface_name_l[IPA_QUOTA_REACH_IF_NAME_MAX_SIZE];
char iface_name_m[IPA_QUOTA_REACH_IF_NAME_MAX_SIZE];
char *envp[IPA_UEVENT_NUM_EVNP] = {
alert_msg, iface_name_l, iface_name_m, NULL };
int res;
int index;
@ -2434,17 +2633,24 @@ void ipa_broadcast_quota_reach_ind(u32 mux_id)
IPAWANERR("message too long (%d)", res);
return;
}
res = snprintf(iface_name, IPA_QUOTA_REACH_IF_NAME_MAX_SIZE,
/* posting msg for L-release for CNE */
res = snprintf(iface_name_l, IPA_QUOTA_REACH_IF_NAME_MAX_SIZE,
"UPSTREAM=%s", mux_channel[index].vchannel_name);
if (IPA_QUOTA_REACH_IF_NAME_MAX_SIZE <= res) {
IPAWANERR("message too long (%d)", res);
return;
}
/* posting msg for M-release for CNE */
res = snprintf(iface_name_m, IPA_QUOTA_REACH_IF_NAME_MAX_SIZE,
"INTERFACE=%s", mux_channel[index].vchannel_name);
if (IPA_QUOTA_REACH_IF_NAME_MAX_SIZE <= res) {
IPAWANERR("message too long (%d)", res);
return;
}
IPAWANDBG("putting nlmsg: <%s> <%s>\n", alert_msg, iface_name);
IPAWANERR("putting nlmsg: <%s> <%s> <%s>\n",
alert_msg, iface_name_l, iface_name_m);
kobject_uevent_env(&(ipa_netdevs[0]->dev.kobj), KOBJ_CHANGE, envp);
return;
}
/**

View file

@ -35,6 +35,18 @@
#define WAN_IOC_SET_DATA_QUOTA32 _IOWR(WAN_IOC_MAGIC, \
WAN_IOCTL_SET_DATA_QUOTA, \
compat_uptr_t)
#define WAN_IOC_SET_TETHER_CLIENT_PIPE32 _IOWR(WAN_IOC_MAGIC, \
WAN_IOCTL_SET_TETHER_CLIENT_PIPE, \
compat_uptr_t)
#define WAN_IOC_QUERY_TETHER_STATS32 _IOWR(WAN_IOC_MAGIC, \
WAN_IOCTL_QUERY_TETHER_STATS, \
compat_uptr_t)
#define WAN_IOC_RESET_TETHER_STATS32 _IOWR(WAN_IOC_MAGIC, \
WAN_IOCTL_RESET_TETHER_STATS, \
compat_uptr_t)
#define WAN_IOC_QUERY_DL_FILTER_STATS32 _IOWR(WAN_IOC_MAGIC, \
WAN_IOCTL_QUERY_DL_FILTER_STATS, \
compat_uptr_t)
#endif
static unsigned int dev_num = 1;
@ -182,6 +194,75 @@ static long wan_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
break;
case WAN_IOC_SET_TETHER_CLIENT_PIPE:
IPAWANDBG("device %s got WAN_IOC_SET_TETHER_CLIENT_PIPE :>>>\n",
DRIVER_NAME);
pyld_sz = sizeof(struct wan_ioctl_set_tether_client_pipe);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
break;
}
if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
retval = -EFAULT;
break;
}
if (rmnet_ipa_set_tether_client_pipe(
(struct wan_ioctl_set_tether_client_pipe *)param)) {
IPAWANERR("WAN_IOC_SET_TETHER_CLIENT_PIPE failed\n");
retval = -EFAULT;
break;
}
break;
case WAN_IOC_QUERY_TETHER_STATS:
IPAWANDBG("device %s got WAN_IOC_QUERY_TETHER_STATS :>>>\n",
DRIVER_NAME);
pyld_sz = sizeof(struct wan_ioctl_query_tether_stats);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
break;
}
if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
retval = -EFAULT;
break;
}
if (rmnet_ipa_query_tethering_stats(
(struct wan_ioctl_query_tether_stats *)param, false)) {
IPAWANERR("WAN_IOC_QUERY_TETHER_STATS failed\n");
retval = -EFAULT;
break;
}
if (copy_to_user((u8 *)arg, param, pyld_sz)) {
retval = -EFAULT;
break;
}
break;
case WAN_IOC_RESET_TETHER_STATS:
IPAWANDBG("device %s got WAN_IOC_RESET_TETHER_STATS :>>>\n",
DRIVER_NAME);
pyld_sz = sizeof(struct wan_ioctl_reset_tether_stats);
param = kzalloc(pyld_sz, GFP_KERNEL);
if (!param) {
retval = -ENOMEM;
break;
}
if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
retval = -EFAULT;
break;
}
if (rmnet_ipa_query_tethering_stats(NULL, true)) {
IPAWANERR("WAN_IOC_QUERY_TETHER_STATS failed\n");
retval = -EFAULT;
break;
}
break;
default:
retval = -ENOTTY;
}
@ -205,6 +286,18 @@ long compat_wan_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case WAN_IOC_SET_DATA_QUOTA32:
cmd = WAN_IOC_SET_DATA_QUOTA;
break;
case WAN_IOC_SET_TETHER_CLIENT_PIPE32:
cmd = WAN_IOC_SET_TETHER_CLIENT_PIPE;
break;
case WAN_IOC_QUERY_TETHER_STATS32:
cmd = WAN_IOC_QUERY_TETHER_STATS;
break;
case WAN_IOC_RESET_TETHER_STATS32:
cmd = WAN_IOC_RESET_TETHER_STATS;
break;
case WAN_IOC_QUERY_DL_FILTER_STATS32:
cmd = WAN_IOC_QUERY_DL_FILTER_STATS;
break;
default:
return -ENOIOCTLCMD;
}

View file

@ -1327,6 +1327,15 @@ int teth_bridge_disconnect(enum ipa_client_type client);
int teth_bridge_connect(struct teth_bridge_connect_params *connect_params);
/*
* Tethering client info
*/
void ipa_set_client(int index, enum ipacm_client_enum client, bool uplink);
enum ipacm_client_enum ipa_get_client(int pipe_idx);
bool ipa_get_client_uplink(int pipe_idx);
/*
* ODU bridge
*/
@ -1939,6 +1948,25 @@ static inline int teth_bridge_connect(struct teth_bridge_connect_params
return -EPERM;
}
/*
* Tethering client info
*/
static inline void ipa_set_client(int index, enum ipacm_client_enum client,
bool uplink)
{
}
static inline enum ipacm_client_enum ipa_get_client(int pipe_idx)
{
return -EPERM;
}
static inline bool ipa_get_client_uplink(int pipe_idx)
{
return -EPERM;
}
/*
* ODU bridge
*/