blob: d37920e1fb5269054baf685cb19686e4385f7ffc [file] [log] [blame]
/* Copyright (c) 2017, 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ipa_ut_framework.h"
#include <linux/netdevice.h>
struct ipa_test_hw_stats_ctx {
u32 odu_prod_hdl;
u32 odu_cons_hdl;
u32 rt4_usb;
u32 rt6_usb;
u32 rt4_odu_cons;
u32 rt6_odu_cons;
atomic_t odu_pending;
};
static struct ipa_test_hw_stats_ctx *ctx;
static int ipa_test_hw_stats_suite_setup(void **ppriv)
{
IPA_UT_DBG("Start Setup\n");
if (!ctx)
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
return 0;
}
static int ipa_test_hw_stats_suite_teardown(void *priv)
{
IPA_UT_DBG("Start Teardown\n");
return 0;
}
static void odu_prod_notify(void *priv, enum ipa_dp_evt_type evt,
unsigned long data)
{
struct sk_buff *skb = (struct sk_buff *)data;
switch (evt) {
case IPA_RECEIVE:
dev_kfree_skb_any(skb);
break;
case IPA_WRITE_DONE:
atomic_dec(&ctx->odu_pending);
dev_kfree_skb_any(skb);
break;
default:
IPA_UT_ERR("unexpected evt %d\n", evt);
}
}
static void odu_cons_notify(void *priv, enum ipa_dp_evt_type evt,
unsigned long data)
{
struct sk_buff *skb = (struct sk_buff *)data;
int ret;
switch (evt) {
case IPA_RECEIVE:
if (atomic_read(&ctx->odu_pending) >= 64)
msleep(20);
atomic_inc(&ctx->odu_pending);
skb_put(skb, 100);
ret = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, NULL);
while (ret) {
msleep(100);
ret = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, NULL);
}
break;
case IPA_WRITE_DONE:
dev_kfree_skb_any(skb);
break;
default:
IPA_UT_ERR("unexpected evt %d\n", evt);
}
}
static int ipa_test_hw_stats_configure(void *priv)
{
struct ipa_sys_connect_params odu_prod_params;
struct ipa_sys_connect_params odu_emb_cons_params;
int res;
/* first connect all additional pipe */
memset(&odu_prod_params, 0, sizeof(odu_prod_params));
memset(&odu_emb_cons_params, 0, sizeof(odu_emb_cons_params));
odu_prod_params.client = IPA_CLIENT_ODU_PROD;
odu_prod_params.desc_fifo_sz = 0x1000;
odu_prod_params.priv = NULL;
odu_prod_params.notify = odu_prod_notify;
res = ipa_setup_sys_pipe(&odu_prod_params,
&ctx->odu_prod_hdl);
if (res) {
IPA_UT_ERR("fail to setup sys pipe ODU_PROD %d\n", res);
return res;
}
odu_emb_cons_params.client = IPA_CLIENT_ODU_EMB_CONS;
odu_emb_cons_params.desc_fifo_sz = 0x1000;
odu_emb_cons_params.priv = NULL;
odu_emb_cons_params.notify = odu_cons_notify;
res = ipa_setup_sys_pipe(&odu_emb_cons_params,
&ctx->odu_cons_hdl);
if (res) {
IPA_UT_ERR("fail to setup sys pipe ODU_EMB_CONS %d\n", res);
ipa_teardown_sys_pipe(ctx->odu_prod_hdl);
return res;
}
IPA_UT_INFO("Configured. Please connect USB RNDIS now\n");
return 0;
}
static int ipa_test_hw_stats_add_FnR(void *priv)
{
struct ipa_ioc_add_rt_rule *rt_rule;
struct ipa_ioc_add_flt_rule *flt_rule;
struct ipa_ioc_get_rt_tbl rt_lookup;
int ret;
rt_rule = kzalloc(sizeof(*rt_rule) + 1 * sizeof(struct ipa_rt_rule_add),
GFP_KERNEL);
if (!rt_rule) {
IPA_UT_DBG("no mem\n");
return -ENOMEM;
}
flt_rule = kzalloc(sizeof(*flt_rule) +
1 * sizeof(struct ipa_flt_rule_add), GFP_KERNEL);
if (!flt_rule) {
IPA_UT_DBG("no mem\n");
ret = -ENOMEM;
goto free_rt;
}
rt_rule->commit = 1;
rt_rule->ip = IPA_IP_v4;
rt_lookup.ip = rt_rule->ip;
strlcpy(rt_rule->rt_tbl_name, "V4_RT_TO_USB_CONS",
IPA_RESOURCE_NAME_MAX);
strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
rt_rule->num_rules = 1;
rt_rule->rules[0].rule.dst = IPA_CLIENT_USB_CONS;
rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
rt_rule->rules[0].rule.attrib.dst_port = 5002;
rt_rule->rules[0].rule.hashable = true;
if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
IPA_UT_ERR("failed to install V4 rules\n");
ret = -EFAULT;
goto free_flt;
}
if (ipa_get_rt_tbl(&rt_lookup)) {
IPA_UT_ERR("failed to query V4 rules\n");
ret = -EFAULT;
goto free_flt;
}
ctx->rt4_usb = rt_lookup.hdl;
memset(rt_rule, 0, sizeof(*rt_rule));
rt_rule->commit = 1;
rt_rule->ip = IPA_IP_v6;
rt_lookup.ip = rt_rule->ip;
strlcpy(rt_rule->rt_tbl_name, "V6_RT_TO_USB_CONS",
IPA_RESOURCE_NAME_MAX);
strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
rt_rule->num_rules = 1;
rt_rule->rules[0].rule.dst = IPA_CLIENT_USB_CONS;
rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
rt_rule->rules[0].rule.attrib.dst_port = 5002;
rt_rule->rules[0].rule.hashable = true;
if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
IPA_UT_ERR("failed to install V4 rules\n");
ret = -EFAULT;
goto free_flt;
}
if (ipa_get_rt_tbl(&rt_lookup)) {
IPA_UT_ERR("failed to query V4 rules\n");
ret = -EFAULT;
goto free_flt;
}
ctx->rt6_usb = rt_lookup.hdl;
memset(rt_rule, 0, sizeof(*rt_rule));
rt_rule->commit = 1;
rt_rule->ip = IPA_IP_v4;
rt_lookup.ip = rt_rule->ip;
strlcpy(rt_rule->rt_tbl_name, "V4_RT_TO_ODU_CONS",
IPA_RESOURCE_NAME_MAX);
strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
rt_rule->num_rules = 1;
rt_rule->rules[0].rule.dst = IPA_CLIENT_ODU_EMB_CONS;
rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
rt_rule->rules[0].rule.attrib.dst_port = 5002;
rt_rule->rules[0].rule.hashable = true;
if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
IPA_UT_ERR("failed to install V4 rules\n");
ret = -EFAULT;
goto free_flt;
}
if (ipa_get_rt_tbl(&rt_lookup)) {
IPA_UT_ERR("failed to query V4 rules\n");
return -EFAULT;
}
ctx->rt4_odu_cons = rt_lookup.hdl;
memset(rt_rule, 0, sizeof(*rt_rule));
rt_rule->commit = 1;
rt_rule->ip = IPA_IP_v6;
rt_lookup.ip = rt_rule->ip;
strlcpy(rt_rule->rt_tbl_name, "V6_RT_TO_ODU_CONS",
IPA_RESOURCE_NAME_MAX);
strlcpy(rt_lookup.name, rt_rule->rt_tbl_name, IPA_RESOURCE_NAME_MAX);
rt_rule->num_rules = 1;
rt_rule->rules[0].rule.dst = IPA_CLIENT_ODU_EMB_CONS;
rt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
rt_rule->rules[0].rule.attrib.dst_port = 5002;
rt_rule->rules[0].rule.hashable = true;
if (ipa_add_rt_rule(rt_rule) || rt_rule->rules[0].status) {
IPA_UT_ERR("failed to install V4 rules\n");
ret = -EFAULT;
goto free_flt;
}
if (ipa_get_rt_tbl(&rt_lookup)) {
IPA_UT_ERR("failed to query V4 rules\n");
ret = -EFAULT;
goto free_flt;
}
ctx->rt6_odu_cons = rt_lookup.hdl;
flt_rule->commit = 1;
flt_rule->ip = IPA_IP_v4;
flt_rule->ep = IPA_CLIENT_USB_PROD;
flt_rule->num_rules = 1;
flt_rule->rules[0].at_rear = 1;
flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
flt_rule->rules[0].rule.attrib.dst_port = 5002;
flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt4_odu_cons;
flt_rule->rules[0].rule.hashable = 1;
if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
IPA_UT_ERR("failed to install V4 rules\n");
ret = -EFAULT;
goto free_flt;
}
memset(flt_rule, 0, sizeof(*flt_rule));
flt_rule->commit = 1;
flt_rule->ip = IPA_IP_v6;
flt_rule->ep = IPA_CLIENT_USB_PROD;
flt_rule->num_rules = 1;
flt_rule->rules[0].at_rear = 1;
flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
flt_rule->rules[0].rule.attrib.dst_port = 5002;
flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt6_odu_cons;
flt_rule->rules[0].rule.hashable = 1;
if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
IPA_UT_ERR("failed to install V6 rules\n");
ret = -EFAULT;
goto free_flt;
}
memset(flt_rule, 0, sizeof(*flt_rule));
flt_rule->commit = 1;
flt_rule->ip = IPA_IP_v4;
flt_rule->ep = IPA_CLIENT_ODU_PROD;
flt_rule->num_rules = 1;
flt_rule->rules[0].at_rear = 1;
flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
flt_rule->rules[0].rule.attrib.dst_port = 5002;
flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt4_usb;
flt_rule->rules[0].rule.hashable = 1;
if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
IPA_UT_ERR("failed to install V4 rules\n");
ret = -EFAULT;
goto free_flt;
}
memset(flt_rule, 0, sizeof(*flt_rule));
flt_rule->commit = 1;
flt_rule->ip = IPA_IP_v6;
flt_rule->ep = IPA_CLIENT_ODU_PROD;
flt_rule->num_rules = 1;
flt_rule->rules[0].at_rear = 1;
flt_rule->rules[0].rule.action = IPA_PASS_TO_ROUTING;
flt_rule->rules[0].rule.attrib.attrib_mask = IPA_FLT_DST_PORT;
flt_rule->rules[0].rule.attrib.dst_port = 5002;
flt_rule->rules[0].rule.rt_tbl_hdl = ctx->rt6_usb;
flt_rule->rules[0].rule.hashable = 1;
if (ipa_add_flt_rule(flt_rule) || flt_rule->rules[0].status) {
IPA_UT_ERR("failed to install V6 rules\n");
ret = -EFAULT;
goto free_flt;
}
IPA_UT_INFO(
"Rules added. Please start data transfer on ports 5001/5002\n");
ret = 0;
free_flt:
kfree(flt_rule);
free_rt:
kfree(rt_rule);
return ret;
}
/* Suite definition block */
IPA_UT_DEFINE_SUITE_START(hw_stats, "HW stats test",
ipa_test_hw_stats_suite_setup, ipa_test_hw_stats_suite_teardown)
{
IPA_UT_ADD_TEST(configure, "Configure the setup",
ipa_test_hw_stats_configure, false, IPA_HW_v4_0, IPA_HW_MAX),
IPA_UT_ADD_TEST(add_rules, "Add FLT and RT rules",
ipa_test_hw_stats_add_FnR, false, IPA_HW_v4_0, IPA_HW_MAX),
} IPA_UT_DEFINE_SUITE_END(hw_stats);