From patchwork Wed Nov 16 18:00:05 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Van Haaren, Harry" X-Patchwork-Id: 17051 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 113D45A0A; Wed, 16 Nov 2016 19:01:28 +0100 (CET) Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by dpdk.org (Postfix) with ESMTP id DA93B567E for ; Wed, 16 Nov 2016 19:00:26 +0100 (CET) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP; 16 Nov 2016 10:00:25 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.31,649,1473145200"; d="scan'208"; a="1069396489" Received: from sie-lab-212-222.ir.intel.com (HELO silpixa00398672.ir.intel.com) ([10.237.212.222]) by fmsmga001.fm.intel.com with ESMTP; 16 Nov 2016 10:00:24 -0800 From: Harry van Haaren To: dev@dpdk.org Cc: Harry van Haaren , Gage Eads , David Hunt Date: Wed, 16 Nov 2016 18:00:05 +0000 Message-Id: <1479319207-130646-6-git-send-email-harry.van.haaren@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1479319207-130646-1-git-send-email-harry.van.haaren@intel.com> References: <1479319207-130646-1-git-send-email-harry.van.haaren@intel.com> Subject: [dpdk-dev] [PATCH 5/7] test/eventdev: unit and functional tests X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This commit adds basic unit and functional tests for the eventdev API. The test code is added in this commit, but not yet enabled until the next commit. Signed-off-by: Gage Eads Signed-off-by: David Hunt Signed-off-by: Harry van Haaren --- app/test/test_eventdev_func.c | 1268 +++++++++++++++++++++++++++++++++++++++++ app/test/test_eventdev_unit.c | 557 ++++++++++++++++++ 2 files changed, 1825 insertions(+) create mode 100644 app/test/test_eventdev_func.c create mode 100644 app/test/test_eventdev_unit.c diff --git a/app/test/test_eventdev_func.c b/app/test/test_eventdev_func.c new file mode 100644 index 0000000..d7fe481 --- /dev/null +++ b/app/test/test_eventdev_func.c @@ -0,0 +1,1268 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "test.h" + +#define MAX_PORTS 16 +#define MAX_QIDS 16 +#define NUM_PACKETS (1<<18) + +struct test { + struct rte_mempool *mbuf_pool; + int ev; + int port[MAX_PORTS]; + int qid[MAX_QIDS]; + int nb_qids; +}; + +static inline struct rte_mbuf * +rte_gen_arp(int portid, struct rte_mempool *mp) +{ + /* + * len = 14 + 46 + * ARP, Request who-has 10.0.0.1 tell 10.0.0.2, length 46 + */ + static const uint8_t arp_request[] = { + /*0x0000:*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xa8, + 0x6b, 0xfd, 0x02, 0x29, 0x08, 0x06, 0x00, 0x01, + /*0x0010:*/ 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xec, 0xa8, + 0x6b, 0xfd, 0x02, 0x29, 0x0a, 0x00, 0x00, 0x01, + /*0x0020:*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /*0x0030:*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + struct rte_mbuf *m; + int pkt_len = sizeof(arp_request) - 1; + + m = rte_pktmbuf_alloc(mp); + if (!m) + return 0; + + memcpy((void *)((uint64_t)m->buf_addr + m->data_off), + arp_request, pkt_len); + rte_pktmbuf_pkt_len(m) = pkt_len; + rte_pktmbuf_data_len(m) = pkt_len; + + RTE_SET_USED(portid); + /* + * Ignore MAC address for super-simple testing + * struct ether_addr mac_addr; + * rte_eth_macaddr_get(portid, &mac_addr); + * memcpy((void *)((uint64_t)m->buf_addr + m->data_off + 6), + * &mac_addr, 6); + */ + + return m; +} + +/* initialization and config */ +static inline int +init(struct test *t, int nb_queues, int nb_ports) +{ + struct rte_event_dev_config config = { + .nb_event_queues = nb_queues, + .nb_event_ports = nb_ports, + }; + int ret, nevdevs = rte_event_dev_count(); + + void *temp = t->mbuf_pool; /* save and restore mbuf pool */ + + memset(t, 0, sizeof(*t)); + t->mbuf_pool = temp; + + if (nevdevs < 1) { + printf("%d: No Eventdev Devices Found\n", __LINE__); + return -1; + } + + const char *eventdev_name = "evdev_sw0"; + + t->ev = rte_event_dev_get_dev_id(eventdev_name); + if (t->ev < 0) { + printf("%d: Eventdev %s not found - quitting.\n", __LINE__, eventdev_name); + return -1; + } + + ret = rte_event_dev_configure(t->ev, &config); + if (ret < 0) + printf("%d: Error configuring device\n", __LINE__); + return ret; +}; + +static inline int +create_ports(struct test *t, int num_ports) +{ + int i; + static const struct rte_event_port_conf conf = { + .dequeue_queue_depth = 32, + .enqueue_queue_depth = 64, + }; + + for (i = 0; i < num_ports; i++) { + if (rte_event_port_setup(t->ev, i, &conf) < 0) { + printf("Error setting up port %d\n", i); + return -1; + } + t->port[i] = i; + } + + return 0; +} + +static inline int +create_atomic_qids(struct test *t, int num_qids) +{ + int i; + + /* Q creation */ + static const struct rte_event_queue_conf conf = { + .priority = RTE_EVENT_QUEUE_PRIORITY_NORMAL, + .nb_atomic_flows = 1024, + }; + + for (i = t->nb_qids; i < t->nb_qids + num_qids; i++) { + if (rte_event_queue_setup(t->ev, i, &conf) < 0) { + printf("%d: error creating qid %d\n", __LINE__, i); + return -1; + } + t->qid[i] = i; + } + t->nb_qids += num_qids; + + return 0; +} + +static inline int +create_ordered_qids(struct test *t, int num_qids) +{ + int i; + + /* Q creation */ + static const struct rte_event_queue_conf conf = { + .priority = RTE_EVENT_QUEUE_PRIORITY_NORMAL, + .nb_atomic_order_sequences = 1024, + }; + + for (i = t->nb_qids; i < t->nb_qids + num_qids; i++) { + if (rte_event_queue_setup(t->ev, i, &conf) < 0) { + printf("%d: error creating qid %d\n", __LINE__, i); + return -1; + } + t->qid[i] = i; + } + t->nb_qids += num_qids; + + return 0; +} + +static inline int +create_unordered_qids(struct test *t, int num_qids) +{ + int i; + + /* Q creation */ + static const struct rte_event_queue_conf conf = { + .priority = RTE_EVENT_QUEUE_PRIORITY_NORMAL, + }; + + for (i = t->nb_qids; i < t->nb_qids + num_qids; i++) { + if (rte_event_queue_setup(t->ev, i, &conf) < 0) { + printf("%d: error creating qid %d\n", __LINE__, i); + return -1; + } + t->qid[i] = i; + } + t->nb_qids += num_qids; + + return 0; +} + +static inline int +create_directed_qids(struct test *t, int num_qids, int ports[]) +{ + int i; + + /* Q creation */ + static const struct rte_event_queue_conf conf = { + .priority = RTE_EVENT_QUEUE_PRIORITY_NORMAL, + .event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_CONSUMER, + }; + + for (i = t->nb_qids; i < t->nb_qids + num_qids; i++) { + struct rte_event_queue_link link; + + if (rte_event_queue_setup(t->ev, i, &conf) < 0) { + printf("%d: error creating qid %d\n", __LINE__, i); + return -1; + } + t->qid[i] = i; + + link = (struct rte_event_queue_link){ + t->qid[i], + RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL + }; + if (rte_event_port_link(t->ev, ports[i - t->nb_qids], &link, 1) != 1) { + printf("%d: error creating link for qid %d\n", + __LINE__, i); + return -1; + } + } + t->nb_qids += num_qids; + + return 0; +} + +/* destruction */ +static inline int +cleanup(struct test *t) +{ + rte_event_dev_stop(t->ev); + rte_event_dev_close(t->ev); + return 0; +}; + +/* run_prio_packet_test + * This performs a basic packet priority check on the test instance passed in. + * It is factored out of the main priority tests as the same tests must be + * performed to ensure prioritization of each type of QID. + * + * Requirements: + * - An initialized test structure, including mempool + * - t->port[0] is initialized for both Enq / Deq of packets to the QID + * - t->qid[0] is the QID to be tested + * - if LB QID, the CQ must be mapped to the QID. + */ +static int +run_prio_packet_test(struct test *t) +{ + int err; + const uint32_t MAGIC_SEQN[] = {4711, 1234}; + const uint32_t PRIORITY[] = {3, 0}; + unsigned i; + for(i = 0; i < RTE_DIM(MAGIC_SEQN); i++) { + /* generate pkt and enqueue */ + struct rte_event ev; + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + arp->seqn = MAGIC_SEQN[i]; + + ev = (struct rte_event){ + .priority = PRIORITY[i], + .operation = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0], + .mbuf = arp + }; + err = rte_event_enqueue(t->ev, t->port[0], &ev, 0); + if (err < 0) { + printf("%d: error failed to enqueue\n", __LINE__); + return -1; + } + } + + rte_event_schedule(t->ev); + + struct rte_event_dev_stats stats; + err = rte_event_dev_stats_get(t->ev, &stats); + if (err) { + printf("%d: error failed to get stats\n", __LINE__); + return -1; + } + + if (stats.port_rx_pkts[t->port[0]] != 2) { + printf("%d: error stats incorrect for directed port\n", __LINE__); + rte_event_dev_dump(stdout, t->ev); + return -1; + } + + struct rte_event ev, ev2; + uint32_t deq_pkts; + deq_pkts = rte_event_dequeue(t->ev, t->port[0], &ev, 0); + if (deq_pkts != 1) { + printf("%d: error failed to deq\n", __LINE__); + rte_event_dev_dump(stdout, t->ev); + return -1; + } + if(ev.mbuf->seqn != MAGIC_SEQN[1]) { + printf("%d: first packet out not highest priority\n", __LINE__); + rte_event_dev_dump(stdout, t->ev); + return -1; + } + rte_pktmbuf_free(ev.mbuf); + + deq_pkts = rte_event_dequeue(t->ev, t->port[0], &ev2, 0); + if (deq_pkts != 1) { + printf("%d: error failed to deq\n", __LINE__); + rte_event_dev_dump(stdout, t->ev); + return -1; + } + if(ev2.mbuf->seqn != MAGIC_SEQN[0]) { + printf("%d: second packet out not lower priority\n", __LINE__); + rte_event_dev_dump(stdout, t->ev); + return -1; + } + rte_pktmbuf_free(ev2.mbuf); + + cleanup(t); + return 0; +} + +static int +test_single_directed_packet(struct test *t) +{ + const int rx_enq = 0; + const int wrk_enq = 2; + int err; + + /* Create instance with 3 directed QIDs going to 3 ports */ + if (init(t, 3, 3) < 0 || + create_ports(t, 3) < 0 || + create_directed_qids(t, 3, t->port) < 0) + return -1; + + if (rte_event_dev_start(t->ev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /************** FORWARD ****************/ + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + struct rte_event ev = { + .operation = RTE_EVENT_OP_NEW, + .queue_id = wrk_enq, + .mbuf = arp, + }; + + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + + const uint32_t MAGIC_SEQN = 4711; + arp->seqn = MAGIC_SEQN; + + /* generate pkt and enqueue */ + err = rte_event_enqueue(t->ev, rx_enq, &ev, 0); + if (err < 0) { + printf("%d: error failed to enqueue\n", __LINE__); + return -1; + } + + /* Run schedule() as dir packets may need to be re-ordered */ + if (rte_event_schedule(t->ev) < 0) { + printf("%d: Error with schedule call\n", __LINE__); + return -1; + } + + struct rte_event_dev_stats stats; + err = rte_event_dev_stats_get(t->ev, &stats); + if (err) { + printf("%d: error failed to get stats\n", __LINE__); + return -1; + } + + if (stats.port_rx_pkts[rx_enq] != 1) { + printf("%d: error stats incorrect for directed port\n", __LINE__); + return -1; + } + + uint32_t deq_pkts; + deq_pkts = rte_event_dequeue(t->ev, wrk_enq, &ev, 1); + if (deq_pkts != 1) { + printf("%d: error failed to deq\n", __LINE__); + return -1; + } + + err = rte_event_dev_stats_get(t->ev, &stats); + if (stats.port_rx_pkts[wrk_enq] != 0 && + stats.port_rx_pkts[wrk_enq] != 1) { + printf("%d: error directed stats post-dequeue\n", __LINE__); + return -1; + } + + if (ev.mbuf->seqn != MAGIC_SEQN) { + printf("%d: error magic sequence number not dequeued\n", __LINE__); + return -1; + } + + rte_pktmbuf_free(ev.mbuf); + cleanup(t); + return 0; +} + +static int +test_overload_trip(struct test *t) +{ + int err; + + /* Create instance with 3 directed QIDs going to 3 ports */ + if (init(t, 1, 1) < 0 || + create_ports(t, 1) < 0 || + create_atomic_qids(t, 1) < 0) + return -1; + + struct rte_event_queue_link link = {t->qid[0], + RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL }; + int ret = rte_event_port_link(t->ev, t->port[0], &link, 1); + if (ret != 1) { + printf("%d: error mapping lb qid0\n", __LINE__); + return -1; + } + + if (rte_event_dev_start(t->ev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + + /* 512 packets is threshold + * iters 0 - 511 is 512 packets, then overload will be flagged + * iter 512 (the 513th pkt) is the first refused NEW packet */ + const uint32_t THRES = (256+1); + uint32_t i; + for (i = 0; i < THRES; i++) { + struct rte_event ev = { + .operation = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0], + .mbuf = arp, + }; + err = rte_event_enqueue(t->ev, 0, &ev, 0); + if(i == THRES-1) { + if(err != -ENOSPC) { + printf("%d: overload trip didn't cause NEW pkt enq fail\n", __LINE__); + return -1; + } + else { + //printf("iter %d -ENOSPC returned for new enq as expected.\n", i); + } + } else { + if (err < 0) { + printf("%d: error failed to enqueue\n", __LINE__); + return -1; + } + } + } + + for (i = 0; i < THRES; i++) { + if (rte_event_schedule(t->ev) < 0) { + printf("%d: Error with schedule call\n", __LINE__); + return -1; + } + + uint32_t deq_pkts; + struct rte_event ev; + deq_pkts = rte_event_dequeue(t->ev, 0, &ev, 1); + + /* i == THRES-1 *should* fail to deq, due to NEW pkt rejection + * when enqueue is attempted in overload mode */ + if (i == (THRES-1) && deq_pkts == 0) + break; + + if (deq_pkts != 1) { + printf("%d: warning failed to deq event i = %d\n", + __LINE__, i); + //return -1; + } + } + + rte_pktmbuf_free(arp); + cleanup(t); + return 0; +} + +static int +test_directed_overload(struct test *t) +{ + int err; + + /* Create instance with 3 directed QIDs going to 3 ports */ + if (init(t, 1, 1) < 0 || + create_ports(t, 1) < 0 || + create_directed_qids(t, 1, t->port) < 0) + return -1; + + if (rte_event_dev_start(t->ev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /* 512 packets is threshold + * iters 0 - 511 is 512 packets, then overload will be flagged + * iter 512 (the 513th pkt) is the first refused NEW packet */ + const uint32_t THRES = (256+1); + uint32_t i; + for (i = 0; i < THRES; i++) { + struct rte_event ev = { + .operation = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0], + .event = (uintptr_t)i, + }; + err = rte_event_enqueue(t->ev, 0, &ev, 0); + if(i == THRES-1) { + if(err != -ENOSPC) { + printf("%d: overload trip didn't cause NEW pkt enq fail\n", __LINE__); + //return -1; + } + else { + //printf("iter %d -ENOSPC returned for new enq as expected.\n", i); + } + } else { + if (err < 0) { + printf("%d: error failed to enqueue\n", __LINE__); + return -1; + } + } + } + + if (rte_event_schedule(t->ev) < 0) { + printf("%d: Error with schedule call\n", __LINE__); + return -1; + } + + uint32_t pkt_deq_cntr = 0; + for (i = 0; i < THRES; i++) { + if (rte_event_schedule(t->ev) < 0) { + printf("%d: Error with schedule call\n", __LINE__); + return -1; + } + + int32_t deq_pkts; + struct rte_event ev; + deq_pkts = rte_event_dequeue(t->ev, 0, &ev, 1); + + /* i == THRES-1 *should* fail to deq, due to NEW pkt rejection + * when enqueue is attempted in overload mode */ + if (i == (THRES-1) && deq_pkts == 0) + break; + + if (deq_pkts != 1) { + printf("%d: warning failed to deq (iter = %d), ret %d. Dumping stats\n", + __LINE__, i, deq_pkts); + rte_event_dev_dump(stdout, t->ev); + return -1; + } + pkt_deq_cntr += deq_pkts; + } + + cleanup(t); + return 0; +} + + +static int +test_priority_directed(struct test *t) +{ + if (init(t, 1, 1) < 0 || + create_ports(t, 1) < 0 || + create_directed_qids(t, 1, t->port) < 0) { + printf("%d: Error initialising device\n", __LINE__); + return -1; + } + + if (rte_event_dev_start(t->ev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + return run_prio_packet_test(t); +} + +static int +test_priority_atomic(struct test *t) +{ + if (init(t, 1, 1) < 0 || + create_ports(t, 1) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initialising device\n", __LINE__); + return -1; + } + + /* map the QID */ + struct rte_event_queue_link link = {t->qid[0], + RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL }; + if (rte_event_port_link(t->ev, t->port[0], &link, 1) != 1) { + printf("%d: error mapping qid to port\n", __LINE__); + return -1; + } + if (rte_event_dev_start(t->ev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + return run_prio_packet_test(t); +} + +static int +test_priority_ordered(struct test *t) +{ + if (init(t, 1, 1) < 0 || + create_ports(t, 1) < 0 || + create_ordered_qids(t, 1) < 0) { + printf("%d: Error initialising device\n", __LINE__); + return -1; + } + + /* map the QID */ + struct rte_event_queue_link link = {t->qid[0], + RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL }; + if (rte_event_port_link(t->ev, t->port[0], &link, 1) != 1) { + printf("%d: error mapping qid to port\n", __LINE__); + return -1; + } + if (rte_event_dev_start(t->ev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + return run_prio_packet_test(t); +} + +static int +test_priority_unordered(struct test *t) +{ + if (init(t, 1, 1) < 0 || + create_ports(t, 1) < 0 || + create_unordered_qids(t, 1) < 0) { + printf("%d: Error initialising device\n", __LINE__); + return -1; + } + + /* map the QID */ + struct rte_event_queue_link link = {t->qid[0], + RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL }; + if (rte_event_port_link(t->ev, t->port[0], &link, 1) != 1) { + printf("%d: error mapping qid to port\n", __LINE__); + return -1; + } + if (rte_event_dev_start(t->ev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + return run_prio_packet_test(t); +} + +static int +burst_packets(struct test *t) +{ + /************** CONFIG ****************/ + uint32_t i; + int err; + int ret; + + /* Create instance with 4 ports and 2 queues */ + if (init(t, 2, 2) < 0 || + create_ports(t, 2) < 0 || + create_atomic_qids(t, 2) < 0) { + printf("%d: Error initialising device\n", __LINE__); + return -1; + } + + /* CQ mapping to QID */ + struct rte_event_queue_link link = {t->qid[0], + RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL }; + ret = rte_event_port_link(t->ev, t->port[0], &link, 1); + if (ret != 1) { + printf("%d: error mapping lb qid0\n", __LINE__); + return -1; + } + link.queue_id = t->qid[1]; + ret = rte_event_port_link(t->ev, t->port[1], &link, 1); + if (ret != 1) { + printf("%d: error mapping lb qid1\n", __LINE__); + return -1; + } + + if (rte_event_dev_start(t->ev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /************** FORWARD ****************/ + const uint32_t rx_port = 0; + const uint32_t NUM_PKTS = 2; + + for (i = 0; i < NUM_PKTS; i++) { + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: error generating pkt\n" , __LINE__); + return -1; + } + + struct rte_event ev = { + .operation = RTE_EVENT_OP_NEW, + .queue_id = i % 2, + .flow_id = i % 3, + .mbuf = arp, + }; + /* generate pkt and enqueue */ + err = rte_event_enqueue(t->ev, t->port[rx_port], &ev, 0); + if (err < 1) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + } + int16_t pkts = rte_event_schedule(t->ev); + + RTE_SET_USED(pkts); + + /* Check stats for all NUM_PKTS arrived to sched core */ + struct rte_event_dev_stats stats; + + err = rte_event_dev_stats_get(t->ev, &stats); + if (err) { + printf("%d: failed to get stats\n", __LINE__); + return -1; + } + if (stats.rx_pkts != NUM_PKTS || stats.tx_pkts != NUM_PKTS) { + printf("%d: Sched core didn't receive all %d pkts\n", __LINE__, NUM_PKTS); + rte_event_dev_dump(stdout, t->ev); + return -1; + } + + uint32_t deq_pkts; + int p; + + deq_pkts = 0; + /******** DEQ QID 1 *******/ + do { + struct rte_event ev; + p = rte_event_dequeue(t->ev, t->port[0], &ev, 0); + deq_pkts += p; + rte_pktmbuf_free(ev.mbuf); + } while (p); + + if (deq_pkts != NUM_PKTS/2) { + printf("%d: Half of NUM_PKTS didn't arrive at port 1\n", __LINE__); + return -1; + } + + /******** DEQ QID 2 *******/ + deq_pkts = 0; + do { + struct rte_event ev; + p = rte_event_dequeue(t->ev, t->port[1], &ev, 0); + deq_pkts += p; + rte_pktmbuf_free(ev.mbuf); + } while (p); + if (deq_pkts != NUM_PKTS/2) { + printf("%d: Half of NUM_PKTS didn't arrive at port 2\n", __LINE__); + return -1; + } + + cleanup(t); + return 0; +} + +static int +load_balancing(struct test *t) +{ + const int rx_enq = 0; + int err; + uint32_t i; + + if (init(t, 1, 4) < 0 || + create_ports(t, 4) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initialising device\n", __LINE__); + return -1; + } + + struct rte_event_queue_link link = {t->qid[0], + RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL }; + for (i = 0; i < 3; i++) { + /* map port 1 - 3 inclusive */ + if (rte_event_port_link(t->ev, t->port[i+1], &link, 1) != 1) { + printf("%d: error mapping qid to port %d\n", __LINE__, i); + return -1; + } + } + + if (rte_event_dev_start(t->ev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /************** FORWARD ****************/ + /* + * Create a set of flows that test the load-balancing operation of the + * implementation. Fill CQ 0 and 1 with flows 0 and 1, and test + * with a new flow, which should be sent to the 3rd mapped CQ + */ + static uint32_t flows[] = {0, 1, 1, 0, 0, 2, 2, 0, 2}; +#define PKT_NUM (sizeof(flows) / sizeof(flows[0])) + for (i = 0; i < PKT_NUM; i++) { + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + + struct rte_event ev = { + .operation = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0], + .flow_id = flows[i], + .mbuf = arp, + }; + /* generate pkt and enqueue */ + err = rte_event_enqueue(t->ev, t->port[rx_enq], &ev, 0); + if (err < 1) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + } + + rte_event_schedule(t->ev); + + struct rte_event_dev_stats stats; + err = rte_event_dev_stats_get(t->ev, &stats); + if (err) { + printf("%d: failed to get stats\n", __LINE__); + return -1; + } + + if (stats.port_inflight[1] != 4) { + printf("%d:%s: port 1 inflight not correct\n", __LINE__, __func__); + return -1; + } + if (stats.port_inflight[2] != 2) { + printf("%d:%s: port 2 inflight not correct\n", __LINE__, __func__); + return -1; + } + if (stats.port_inflight[3] != 3) { + printf("%d:%s: port 3 inflight not correct\n", __LINE__, __func__); + return -1; + } + + cleanup(t); + return 0; +} + +static int +invalid_qid(struct test *t) +{ + struct rte_event_dev_stats stats; + const int rx_enq = 0; + int err; + uint32_t i; + + if (init(t, 1, 4) < 0 || + create_ports(t, 4) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initialising device\n", __LINE__); + return -1; + } + + /* CQ mapping to QID */ + for(i = 0; i < 4; i++) { + struct rte_event_queue_link link = {t->qid[0], + RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL }; + err = rte_event_port_link(t->ev, t->port[i], &link, 1); + if (err != 1) { + printf("%d: error mapping port 1 qid\n", __LINE__); + return -1; + } + } + + if (rte_event_dev_start(t->ev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /* + * Send in a packet with an invalid qid to the scheduler. + * We should see the packed enqueued OK, but the inflights for + * that packet should not be incremented, and the rx_dropped + * should be incremented. + */ + static uint32_t flows1[] = {20}; + +#define PKT_NUM1 (sizeof(flows1) / sizeof(flows1[0])) + + for (i = 0; i < PKT_NUM1; i++) { + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + + struct rte_event ev = { + .operation = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0] + flows1[i], + .flow_id = i, + .mbuf = arp, + }; + /* generate pkt and enqueue */ + err = rte_event_enqueue(t->ev, t->port[rx_enq], &ev, 0); + if (err < 1) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + } + + /* call the scheduler */ + int16_t pkts = rte_event_schedule(t->ev); + RTE_SET_USED(pkts); + + err = rte_event_dev_stats_get(t->ev, &stats); + if (err) { + printf("%d: failed to get stats\n", __LINE__); + return -1; + } + + /* + * Now check the resulting inflights on the port, and the rx_dropped. + */ + if (stats.port_inflight[0] != 0) { + printf("%d:%s: port 1 inflight count not correct\n", __LINE__, __func__); + rte_event_dev_dump(stdout, 0); + return -1; + } + if (stats.port_rx_dropped[0] != 1) { + printf("%d:%s: port 1 drops\n", __LINE__, __func__); + rte_event_dev_dump(stdout, 0); + return -1; + } + /* each packet drop should only be counted in one place - port or dev */ + if (stats.rx_dropped != 0) { + printf("%d:%s: port 1 dropped count not correct\n", __LINE__, __func__); + rte_event_dev_dump(stdout, 0); + return -1; + } + + cleanup(t); + return 0; +} + +static int +worker_loopback_worker_fn(void *arg) +{ + struct test *t = arg; + uint8_t port = t->port[1]; + int count = 0; + int err; + + /* + * Takes packets from the input port and then loops them back through + * the Queue Manager. Each packet gets looped through QIDs 0-8, 16 times, + * so each packet goes through 8*16 = 128 times. + */ + printf("%d: \tWorker function started\n", __LINE__); + while (count < NUM_PACKETS) { +#define BURST_SIZE 32 + struct rte_event ev[BURST_SIZE]; + uint16_t i, nb_rx = rte_event_dequeue(t->ev, port, ev, BURST_SIZE); + if (nb_rx == 0) { + rte_pause(); + continue; + } + + for (i = 0; i < nb_rx; i++) { + ev[i].queue_id++; + if (ev[i].queue_id != 8) { + ev[i].operation = RTE_EVENT_OP_FORWARD; + err = rte_event_enqueue(t->ev, port, &ev[i], 0); + if (err <= 0) { + printf("%d: Can't enqueue FWD!!\n", __LINE__); + return -1; + } + continue; + } + + ev[i].queue_id = 0; + ev[i].mbuf->udata64++; + if (ev[i].mbuf->udata64 != 16) { + ev[i].operation = RTE_EVENT_OP_FORWARD; + err = rte_event_enqueue(t->ev, port, &ev[i], 0); + if (err <= 0) { + printf("%d: Can't enqueue FWD!!\n", __LINE__); + return -1; + } + continue; + } + /* we have hit 16 iterations through system - drop */ + rte_pktmbuf_free(ev[i].mbuf); + count++; + ev[i].operation = RTE_EVENT_OP_DROP; + err = rte_event_enqueue(t->ev, port, &ev[i], 0); + if(err != 1) { + printf("%d drop enqueue failed\n", __LINE__); + return -1; + } + } + } + + return 0; +} + +static int +worker_loopback_producer_fn(void *arg) +{ + struct test *t = arg; + uint8_t port = t->port[0]; + uint64_t count = 0; + + printf("%d: \tProducer function started\n", __LINE__); + while (count < NUM_PACKETS) { + struct rte_mbuf *m = rte_pktmbuf_alloc(t->mbuf_pool); + if (m == NULL) { + printf("%d: Error allocating mbuf\n", __LINE__); + return -1; + } + m->udata64 = 0; + + struct rte_event ev = { + .operation = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0], + .flow_id = (uintptr_t)m & 0xFFFF, + .mbuf = m, + }; + + while (rte_event_enqueue(t->ev, port, &ev, 0) != 1) + rte_pause(); + + count++; + } + + return 0; +} + +static int +worker_loopback(struct test *t) +{ + /* use a single producer core, and a worker core to see what happens + * if the worker loops packets back multiple times + */ + struct rte_event_dev_stats stats; + uint64_t print_cycles = 0, cycles = 0; + uint64_t tx_pkts = 0; + int err; + int w_lcore, p_lcore; + uint32_t i; + + if (init(t, 8, 2) < 0 || + create_ports(t, 2) < 0 || + create_atomic_qids(t, 8) < 0) { + printf("%d: Error initialising device\n", __LINE__); + return -1; + } + + /* CQ mapping to QID */ + for(i = 0; i < 8; i++) { + struct rte_event_queue_link link = {t->qid[i], + RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL }; + err = rte_event_port_link(t->ev, t->port[1], &link, 1); + if (err != 1) { + printf("%d: error mapping port 2 qid %d\n", __LINE__, i); + return -1; + } + } + + if (rte_event_dev_start(t->ev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + p_lcore = rte_get_next_lcore( + /* start core */ -1, + /* skip master */ 1, + /* wrap */ 0); + w_lcore = rte_get_next_lcore(p_lcore, 1, 0); + + rte_eal_remote_launch(worker_loopback_producer_fn, t, p_lcore); + rte_eal_remote_launch(worker_loopback_worker_fn, t, w_lcore); + + print_cycles = cycles = rte_get_timer_cycles(); + while (rte_eal_get_lcore_state(p_lcore) != FINISHED || + rte_eal_get_lcore_state(w_lcore) != FINISHED) { + + rte_event_schedule(t->ev); + + uint64_t new_cycles = rte_get_timer_cycles(); + + if (new_cycles - print_cycles > rte_get_timer_hz()) { + rte_event_dev_stats_get(t->ev, &stats); + printf("%d: \tSched Rx = %" PRIu64 ", Tx = %" PRIu64 "\n", + __LINE__, stats.rx_pkts, stats.tx_pkts); + + print_cycles = new_cycles; + } + if (new_cycles - cycles > rte_get_timer_hz() * 3) { + rte_event_dev_stats_get(t->ev, &stats); + if (stats.tx_pkts == tx_pkts) { + rte_event_dev_dump(stdout, t->ev); + printf("%d: \nNo schedules for seconds, deadlock\n", __LINE__); + return -1; + } + tx_pkts = stats.tx_pkts; + cycles = new_cycles; + } + } + + rte_eal_mp_wait_lcore(); + + //rte_event_dev_dump(stdout, 0); + + cleanup(t); + return 0; +} + +static struct rte_mempool *eventdev_func_mempool; + +static int +test_eventdev(void) +{ + struct test *t = malloc(sizeof(struct test)); + int ret; + + /* Only create mbuf pool once, reuse for each test run */ + if (!eventdev_func_mempool) { + eventdev_func_mempool = rte_pktmbuf_pool_create("EVDEV_SA_MBUF_POOL", + (1<<16), /* size */ + 32 /*MBUF_CACHE_SIZE*/, + 0, + RTE_MBUF_DEFAULT_BUF_SIZE, + rte_socket_id()); + if (!eventdev_func_mempool) { + printf("ERROR creating mempool\n"); + return -1; + } + } + t->mbuf_pool = eventdev_func_mempool; + + printf("*** Running Single Directed Packet test...\n"); + ret = test_single_directed_packet(t); + if (ret != 0) { + printf("ERROR - Single Directed Packet test FAILED.\n"); + return ret; + } + printf("*** Running Overload Trip test...\n"); + ret = test_overload_trip(t); + if (ret != 0) { + printf("ERROR - Overload Trip test FAILED.\n"); + return ret; + } + printf("*** Running Directed Overload test...\n"); + ret = test_directed_overload(t); + if (ret != 0) { + printf("ERROR - Directed Overload test FAILED.\n"); + return ret; + } + printf("*** Running Prioritized Directed test...\n"); + ret = test_priority_directed(t); + if (ret != 0) { + printf("ERROR - Prioritized Directed test FAILED.\n"); + return ret; + } + printf("*** Running Prioritized Atomic test...\n"); + ret = test_priority_atomic(t); + if (ret != 0) { + printf("ERROR - Prioritized Atomic test FAILED.\n"); + return ret; + } + + printf("*** Running Prioritized Ordered test...\n"); + ret = test_priority_ordered(t); + if (ret != 0) { + printf("ERROR - Prioritized Ordered test FAILED.\n"); + return ret; + } + printf("*** Running Prioritized Unordered test...\n"); + ret = test_priority_unordered(t); + if (ret != 0) { + printf("ERROR - Prioritized Unordered test FAILED.\n"); + return ret; + } + printf("*** Running Burst Packets test...\n"); + ret = burst_packets(t); + if (ret != 0) { + printf("ERROR - Burst Packets test FAILED.\n"); + return ret; + } + printf("*** Running Load Balancing test...\n"); + ret = load_balancing(t); + if (ret != 0) { + printf("ERROR - Load Balancing test FAILED.\n"); + return ret; + } + printf("*** Running Invalid QID test...\n"); + ret = invalid_qid(t); + if (ret != 0) { + printf("ERROR - Invalid QID test FAILED.\n"); + return ret; + } + if (rte_lcore_count() >= 3) { + printf("*** Running Worker loopback test...\n"); + ret = worker_loopback(t); + if (ret != 0) { + printf("ERROR - Worker loopback test FAILED.\n"); + return ret; + } + } else { + printf("### Not enough cores for worker loopback test. \n"); + printf("### Need at least 3 cores for test.\n"); + } + /* Free test instance, leaving mempool initialized, and a pointer to it + * in the static eventdev_func_mempool variable. It is re-used on re-runs */ + free(t); + + return 0; +} + +REGISTER_TEST_COMMAND(eventdev_func_autotest, test_eventdev); diff --git a/app/test/test_eventdev_unit.c b/app/test/test_eventdev_unit.c new file mode 100644 index 0000000..c145401 --- /dev/null +++ b/app/test/test_eventdev_unit.c @@ -0,0 +1,557 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include "test.h" +#include +#include +#include + +#include +#include +#include + +typedef enum eventdev_api_ut_ids_s { + EVENTDEV_API_UT_001 = 1, + EVENTDEV_API_UT_002, + EVENTDEV_API_UT_003, + EVENTDEV_API_UT_004, + EVENTDEV_API_UT_005, + EVENTDEV_API_UT_006, + EVENTDEV_API_UT_007, + EVENTDEV_API_UT_008, + EVENTDEV_API_UT_009, + EVENTDEV_API_UT_010, + EVENTDEV_API_UT_011, + EVENTDEV_API_UT_012, + EVENTDEV_API_UT_013, + EVENTDEV_API_UT_014, + EVENTDEV_API_UT_015, + EVENTDEV_API_UT_016, + EVENTDEV_API_UT_017, + EVENTDEV_API_UT_MAX +} eventdev_api_ut_ids_t; + +typedef enum eventdev_tc_status_s { + TC_FAILED, + TC_PASSED +} eventdev_tc_status_t; + +typedef struct eventdev_api_ut_status_s { + bool executed; + eventdev_tc_status_t status; +} eventdev_api_ut_status_t; + +eventdev_api_ut_status_t api_ut_status[EVENTDEV_API_UT_MAX]; + +#define CONFIG_NB_EVENT_QUEUES 2 +#define CONFIG_NB_EVENT_PORTS 2 +#define CONFIG_NB_EVENT_LIMIT 128 + +uint8_t queues[CONFIG_NB_EVENT_QUEUES]; +uint8_t ports[CONFIG_NB_EVENT_PORTS]; + +/* FIXME: Check that dependent tests have executed */ + +static int test_EVENTDEV_API_UT_001_rte_event_dev_count(void) +{ + uint8_t count = rte_event_dev_count(); + + if (count == 1) { + api_ut_status[EVENTDEV_API_UT_001].status = TC_PASSED; + return 0; + } else { + api_ut_status[EVENTDEV_API_UT_001].status = TC_FAILED; + return 1; + } +} + +static int test_EVENTDEV_API_UT_002_rte_event_dev_get_dev_id(void) +{ + int8_t id; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + if (id < 0) { + api_ut_status[EVENTDEV_API_UT_002].status = TC_FAILED; + return 1; + } + + id = rte_event_dev_get_dev_id("evdev_abcd123"); + + if (id >= 0) { + api_ut_status[EVENTDEV_API_UT_002].status = TC_FAILED; + return 1; + } + + api_ut_status[EVENTDEV_API_UT_002].status = TC_PASSED; + return 0; +} + +static int test_EVENTDEV_API_UT_003_rte_event_dev_info_get(void) +{ + struct rte_event_dev_info info; + int8_t id; + int ret; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + ret = rte_event_dev_info_get(id, &info); + if (ret) + goto fail; + + if (strncmp(info.driver_name, "evdev_sw", sizeof("evdev_sw")) != 0) + goto fail; + + /* FIXME: Add checks for remaining fields */ + + api_ut_status[EVENTDEV_API_UT_003].status = TC_PASSED; + return 0; + +fail: + api_ut_status[EVENTDEV_API_UT_003].status = TC_FAILED; + return 1; +} + +static int test_EVENTDEV_API_UT_004_rte_event_dev_configure(void) +{ + struct rte_event_dev_config config; + int8_t id; + int ret; + + api_ut_status[EVENTDEV_API_UT_004].executed = true; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + config.nb_event_queues = CONFIG_NB_EVENT_QUEUES; /* FIXME: Test max */ + config.nb_event_ports = CONFIG_NB_EVENT_PORTS; /* FIXME: Test max */ + config.nb_events_limit = CONFIG_NB_EVENT_LIMIT; /* FIXME: Test max */ + config.dequeue_wait_ns = 0; /* FIXME: Test max */ + + ret = rte_event_dev_configure(id, &config); + if (ret) + goto fail; + + api_ut_status[EVENTDEV_API_UT_004].status = TC_PASSED; + return 0; + +fail: + api_ut_status[EVENTDEV_API_UT_004].status = TC_FAILED; + return 1; +} + +static int test_EVENTDEV_API_UT_005_rte_event_queue_count_pre(void) +{ + int8_t id; + uint8_t count; + + if (!api_ut_status[EVENTDEV_API_UT_004].executed) + test_EVENTDEV_API_UT_004_rte_event_dev_configure(); + if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED) + goto fail; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + count = rte_event_queue_count(id); + if (count != CONFIG_NB_EVENT_QUEUES) + goto fail; + + api_ut_status[EVENTDEV_API_UT_005].status = TC_PASSED; + return 0; + +fail: + api_ut_status[EVENTDEV_API_UT_005].status = TC_FAILED; + return 1; +} + +static int test_EVENTDEV_API_UT_006_rte_event_queue_setup(void) +{ + struct rte_event_queue_conf config; + int8_t id; + int ret; + + api_ut_status[EVENTDEV_API_UT_006].executed = true; + + if (!api_ut_status[EVENTDEV_API_UT_004].executed) + test_EVENTDEV_API_UT_004_rte_event_dev_configure(); + if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED) + goto fail; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + config.event_queue_cfg = 0; + config.priority = 0; + + queues[0] = 0; + + ret = rte_event_queue_setup(id, queues[0], &config); + if (ret < 0) + goto fail; + + config.event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_CONSUMER; + config.priority = 0; + + queues[1] = 1; + + ret = rte_event_queue_setup(id, queues[1], &config); + if (ret < 0) + goto fail; + + api_ut_status[EVENTDEV_API_UT_006].status = TC_PASSED; + return 0; + +fail: + api_ut_status[EVENTDEV_API_UT_006].status = TC_FAILED; + return 1; +} + +static int test_EVENTDEV_API_UT_007_rte_event_queue_count_post(void) +{ + int8_t id; + uint8_t count; + + if (!api_ut_status[EVENTDEV_API_UT_004].executed) + test_EVENTDEV_API_UT_004_rte_event_dev_configure(); + if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED) + goto fail; + + if (!api_ut_status[EVENTDEV_API_UT_006].executed) + test_EVENTDEV_API_UT_006_rte_event_queue_setup(); + if (api_ut_status[EVENTDEV_API_UT_006].status == TC_FAILED) + goto fail; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + count = rte_event_queue_count(id); + if (count != CONFIG_NB_EVENT_QUEUES) + goto fail; + + api_ut_status[EVENTDEV_API_UT_007].status = TC_PASSED; + return 0; + +fail: + api_ut_status[EVENTDEV_API_UT_007].status = TC_FAILED; + return 1; +} + +static int test_EVENTDEV_API_UT_008_rte_event_port_count_pre(void) +{ + int8_t id; + uint8_t count; + + if (!api_ut_status[EVENTDEV_API_UT_004].executed) + test_EVENTDEV_API_UT_004_rte_event_dev_configure(); + if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED) + goto fail; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + count = rte_event_port_count(id); + if (count != CONFIG_NB_EVENT_PORTS) + goto fail; + + api_ut_status[EVENTDEV_API_UT_008].status = TC_PASSED; + return 0; + +fail: + api_ut_status[EVENTDEV_API_UT_008].status = TC_FAILED; + return 1; +} + +static int test_EVENTDEV_API_UT_009_rte_event_port_setup(void) +{ + struct rte_event_port_conf config; + int8_t id; + int ret; + + if (!api_ut_status[EVENTDEV_API_UT_004].executed) + test_EVENTDEV_API_UT_004_rte_event_dev_configure(); + if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED) + goto fail; + + api_ut_status[EVENTDEV_API_UT_009].executed = true; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + config.dequeue_queue_depth = 4; + config.enqueue_queue_depth = 4; + config.new_event_threshold = 64; + + ports[0] = 0; + + ret = rte_event_port_setup(id, ports[0], &config); + if (ret < 0) + goto fail; + + config.dequeue_queue_depth = 4; + config.enqueue_queue_depth = 4; + config.new_event_threshold = 64; + + ports[1] = 1; + + ret = rte_event_port_setup(id, ports[1], &config); + if (ret < 0) + goto fail; + + api_ut_status[EVENTDEV_API_UT_009].status = TC_PASSED; + return 0; + +fail: + api_ut_status[EVENTDEV_API_UT_009].status = TC_FAILED; + return 1; +} + +static int test_EVENTDEV_API_UT_010_rte_event_port_count_post(void) +{ + int8_t id; + uint8_t count; + + if (!api_ut_status[EVENTDEV_API_UT_004].executed) + test_EVENTDEV_API_UT_004_rte_event_dev_configure(); + if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED) + goto fail; + + if (!api_ut_status[EVENTDEV_API_UT_009].executed) + test_EVENTDEV_API_UT_009_rte_event_port_setup(); + if (api_ut_status[EVENTDEV_API_UT_009].status == TC_FAILED) + goto fail; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + count = rte_event_port_count(id); + if (count != CONFIG_NB_EVENT_PORTS) + goto fail; + + api_ut_status[EVENTDEV_API_UT_010].status = TC_PASSED; + return 0; + +fail: + api_ut_status[EVENTDEV_API_UT_010].status = TC_FAILED; + return 1; +} + +static int test_EVENTDEV_API_UT_011_rte_event_dev_start(void) +{ + int8_t id; + int ret; + + if (!api_ut_status[EVENTDEV_API_UT_004].executed) + test_EVENTDEV_API_UT_004_rte_event_dev_configure(); + if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED) + goto fail; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + ret = rte_event_dev_start(id); + if (ret != 0) + goto fail; + + api_ut_status[EVENTDEV_API_UT_011].status = TC_PASSED; + return 0; + +fail: + api_ut_status[EVENTDEV_API_UT_011].status = TC_FAILED; + return 1; +} + +static int test_EVENTDEV_API_UT_012_rte_event_port_link(void) +{ + struct rte_event_queue_link link; + int8_t id; + int ret; + + if (!api_ut_status[EVENTDEV_API_UT_004].executed) + test_EVENTDEV_API_UT_004_rte_event_dev_configure(); + if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED) + goto fail; + + if (!api_ut_status[EVENTDEV_API_UT_006].executed) + test_EVENTDEV_API_UT_006_rte_event_queue_setup(); + if (api_ut_status[EVENTDEV_API_UT_006].status == TC_FAILED) + goto fail; + + if (!api_ut_status[EVENTDEV_API_UT_009].executed) + test_EVENTDEV_API_UT_009_rte_event_port_setup(); + if (api_ut_status[EVENTDEV_API_UT_009].status == TC_FAILED) + goto fail; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + link.queue_id = queues[0]; + link.priority = 0; + + /* Connect port to previously configured scheduled queue */ + ret = rte_event_port_link(id, ports[0], &link, 1); + if (ret != 1) { + printf("%d: failed here\n", __LINE__); + goto fail; + } + + /* Check idempotency of re-linking port to queues[0] */ + ret = rte_event_port_link(id, ports[0], &link, 1); + if (ret != 1) { + printf("%d: failed here\n", __LINE__); + goto fail; + } + + link.queue_id = queues[1]; + link.priority = 0; + + /* Attempt to connect to FIFO queue as well */ + ret = rte_event_port_link(id, ports[0], &link, 1); + if (ret == 1) { + printf("%d: failed here\n", __LINE__); + goto fail; + } + + link.queue_id = queues[1]; + link.priority = 0; + + /* Connect port to previously configured FIFO queue */ + ret = rte_event_port_link(id, ports[1], &link, 1); + if (ret != 1) { + printf("%d: failed here\n", __LINE__); + goto fail; + } + + link.queue_id = queues[0]; + link.priority = 0; + + /* Attempt to connect to scheduled queue as well */ + ret = rte_event_port_link(id, ports[1], &link, 1); + if (ret == 1) { + printf("%d: failed here\n", __LINE__); + goto fail; + } + + /* link to 2nd queue, enabling start() to pass later */ + link.queue_id = queues[1]; + link.priority = 0; + ret = rte_event_port_link(id, ports[1], &link, 1); + if (ret == 1) { + printf("%d: failed here\n", __LINE__); + goto fail; + } + + api_ut_status[EVENTDEV_API_UT_012].status = TC_PASSED; + return 0; + +fail: + api_ut_status[EVENTDEV_API_UT_012].status = TC_FAILED; + return 1; +} + +static int test_EVENTDEV_API_UT_014_rte_event_dev_stop(void) +{ + int8_t id; + + if (!api_ut_status[EVENTDEV_API_UT_004].executed) + test_EVENTDEV_API_UT_004_rte_event_dev_configure(); + if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED) + return 1; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + rte_event_dev_stop(id); + + api_ut_status[EVENTDEV_API_UT_014].status = TC_PASSED; + return 0; +} + +static int test_EVENTDEV_API_UT_015_rte_event_dev_close(void) +{ + int8_t id; + int ret; + + if (!api_ut_status[EVENTDEV_API_UT_004].executed) + test_EVENTDEV_API_UT_004_rte_event_dev_configure(); + if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED) + goto fail; + + id = rte_event_dev_get_dev_id("evdev_sw0"); + + ret = rte_event_dev_close(id); + if (ret != 0) + goto fail; + + api_ut_status[EVENTDEV_API_UT_015].status = TC_PASSED; + return 0; + +fail: + api_ut_status[EVENTDEV_API_UT_015].status = TC_FAILED; + return 1; +} + +static int +test_setup(void) +{ + return 0; +} + +static struct unit_test_suite eventdev_test_suite = { + .setup = test_setup, + .suite_name = "Eventdev Test Suite", + .unit_test_cases = { + /* device aquisition and config */ + TEST_CASE(test_EVENTDEV_API_UT_001_rte_event_dev_count), + TEST_CASE(test_EVENTDEV_API_UT_002_rte_event_dev_get_dev_id), + TEST_CASE(test_EVENTDEV_API_UT_003_rte_event_dev_info_get), + TEST_CASE(test_EVENTDEV_API_UT_004_rte_event_dev_configure), + /* queue config */ + TEST_CASE(test_EVENTDEV_API_UT_005_rte_event_queue_count_pre), + TEST_CASE(test_EVENTDEV_API_UT_006_rte_event_queue_setup), + TEST_CASE(test_EVENTDEV_API_UT_007_rte_event_queue_count_post), + /* port config */ + TEST_CASE(test_EVENTDEV_API_UT_008_rte_event_port_count_pre), + TEST_CASE(test_EVENTDEV_API_UT_009_rte_event_port_setup), + TEST_CASE(test_EVENTDEV_API_UT_010_rte_event_port_count_post), + TEST_CASE(test_EVENTDEV_API_UT_012_rte_event_port_link), + TEST_CASE(test_EVENTDEV_API_UT_011_rte_event_dev_start), + /* device cleanup */ + TEST_CASE(test_EVENTDEV_API_UT_014_rte_event_dev_stop), + TEST_CASE(test_EVENTDEV_API_UT_015_rte_event_dev_close), + TEST_CASES_END() + } +}; + +static int +test_eventdev_unit(void) +{ + return unit_test_suite_runner(&eventdev_test_suite); +} + +REGISTER_TEST_COMMAND(eventdev_unit_autotest, test_eventdev_unit);