diff options
author | Matias Elo <matias.elo@nokia.com> | 2020-07-03 17:03:49 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-03 17:03:49 +0300 |
commit | aa55e35150da8099ed9f565173993609650010af (patch) | |
tree | 90573ee0b4ff53ff2c080f28b4c66a4e90f0f864 | |
parent | bd75b10924e6df74089d27482dd68bdef33eaf83 (diff) | |
parent | e20ecf15d8af37602a2eb0873d0a91dc5167dd28 (diff) |
Merge ODP v1.24.0.0v1.24.0.0_DPDK_18.11
Merge and port ODP linux-generic v1.24.0.0 commits into odp-dpdk.
106 files changed, 2736 insertions, 611 deletions
diff --git a/.checkpatch.conf b/.checkpatch.conf index 7195642fc..7c179e3e8 100644 --- a/.checkpatch.conf +++ b/.checkpatch.conf @@ -15,5 +15,9 @@ --ignore=CONSTANT_COMPARISON --ignore=BLOCK_COMMENT_STYLE --ignore=UNNECESSARY_PARENTHESES +--ignore=SPDX_LICENSE_TAG +--ignore=PREFER_FALLTHROUGH +--ignore=LONG_LINE_STRING +--ignore=EMAIL_SUBJECT --codespell --codespellfile=/usr/share/codespell/dictionary.txt diff --git a/.travis.yml b/.travis.yml index 1aa85fc96..26b9f1521 100644 --- a/.travis.yml +++ b/.travis.yml @@ -180,6 +180,16 @@ jobs: - docker run --privileged -i -t -v `pwd`:/odp --shm-size 8g -e CC="${CC}" ${DOCKER_NAMESPACE}/travis-odp-ubuntu_20.04-${ARCH} /odp/scripts/ci/build_${ARCH}.sh + - stage: test + env: TEST=gcc-10_lto + compiler: gcc-10 + script: + - if [ -z "${DOCKER_NAMESPACE}" ] ; then export DOCKER_NAMESPACE="opendataplane"; fi + - docker run --privileged -i -t -v `pwd`:/odp --shm-size 8g + -e CC="${CC}" + -e CXX=g++-10 + -e CONF="--enable-lto" + ${DOCKER_NAMESPACE}/travis-odp-ubuntu_20.04-${ARCH} /odp/scripts/ci/build_${ARCH}.sh - stage: "build only" env: TEST=documentation compiler: gcc @@ -220,8 +230,8 @@ jobs: -e CC="${CC}" ${DOCKER_NAMESPACE}/travis-odp-${OS}-${ARCH} /odp/scripts/ci/build_${ARCH}.sh - stage: test - canfail: yes env: TEST=checkpatch + canfail: yes compiler: gcc install: - true @@ -1,3 +1,328 @@ +== OpenDataPlane (1.24.0.0) +=== Summary of Changes + +This release introduces a new stash API module. The other main API additions are +pool buffer caching configuration and packet IO link information. The release +also includes several smaller API improvements and clarifications. + +=== API +==== Common +* Added missing const qualifiers + +Some API calls missed const qualifiers on read-only data pointers. + +* Improved Doxygen module descriptions +* Use param_init functions for parameter defaults + +When available, parameter init functions must be used to initialize parameters +into their default values. + +=== Align +* Added `ODP_CACHE_LINE_ROUNDUP` macro + +Added macro for rounding up a value to the next multiple of cache line size. +This round up is needed e.g. when selecting buffer sizes so that false sharing +is avoided. + +==== CPU +* Make supporting CPU frequency and cycle counter optional + +CPU frequencies or CPU cycle counter may not be available on all HW/SW +platforms. Zero is returned if those cannot be read. + +==== Feature +* Added feature bits `stash` and `compress` into `odp_feature_t`. + +==== Packet +* Clarify packet length function argument definitions + +Modify documentations of functions, which decrease packet length, to clearly +state what are the allowed values for length argument. This is done to avoid +creating zero length packets which are not allowed by the packet API. + +* Added `odp_packet_input_set()` function + +An application may use this for testing or other purposes, when perception of +the packet input interface need to be changed. + +==== Packet I/O +* Added `odp_pktio_link_info()` function for reading link status information +** Autonegotiation mode (unknown/enabled/disabled) +** Duplex mode (unknown/half duplex/full duplex) +** Flow control (unknown/on/off) +** Link status (unknown/up/down) +** Media (media type as string) +** Speed (unknown/Mbps) + +* Modified `odp_pktio_link_status()` to return `odp_pktio_link_status_t` enum +(backward compatible values) + +==== Pool +* Added `cache_size` parameters to `odp_pool_capability_t` and `odp_pool_param_t` + +Added thread local cache size parameter and capability. This allows application +to control thread local caching and prepare large enough pool when +implementation caches events per thread. The default value is implementation +specific for backwards compatibility. + +* Removed default value of packet `max_len` from `odp_pool_param_t` + +The default value is implementation specific and may not be equal to the maximum +capability. + +* Added packet data `align` parameter to `odp_pool_param_t` + +Added packet pool parameter to request minimum data alignment for user allocated +packets. When user allocates a new packet and fills in protocol headers, it's +convenient that data alignment does not need to be checked (and tuned) on each +allocated packet. + +==== Queue +* Unify `max_size capa` specification for all plain queue types + +Specify queue maximum size capability the same way for all non-blocking levels +(`ODP_BLOCKING`, `ODP_NONBLOCKING_LF` and `ODP_NONBLOCKING_WF`). Max_size value +of zero means that there is no size limit. + +* Clarify that queue operations include memory barriers + +Clarify that queue enqueue operations include memory barrier of release +semantics and queue dequeue operations include acquire semantics. + +==== Random +* Clarify how much data `odp_random_data()` and `odp_random_test_data()` output on success. + +It may not be possible for random generator functions to return requested number +of bytes. Clarify that implementation is not required to loop until `len` bytes +are available. Instead application should contain such logic. + +==== Scheduler +* Clarify synchronization of store operations during atomic context + +Stores performed while holding an atomic scheduling context are seen correctly +by other thread when they hold the same context later on. This is guaranteed +also when queue enqueue is not used in between. + +* Clarify that schedule operations include memory barriers + +Clarify that event schedule operations include memory barrier of acquire +semantics. + +==== Shared Memory +* Add `ODP_SHM_HW_ACCESS` flag + +This can be used to memory allocations where both CPUs and HW accelerators +access the same memory area. These HW accelerators may be programmed outside of +ODP APIs, but the memory is reserved and shared normally inside/between ODP +applications. + +==== Stash +* Added new stash API module + +Application needs often store object handles for later usage. From current APIs, +e.g. buffers and queues could be used to store these handles, but buffers +consume more memory than is necessary and event queues are not needed for this +simple use case. This new API maybe implemented e.g. as a ring of object handles +in memory, or with a HW buffer manager. + +==== Time +* Added `odp_time_local_ns()` and `odp_time_global_ns()` functions for acquiring +current time stamp in nanoseconds + +Added functions to get the current local/global +time stamp directly in nanoseconds. For example, `odp_time_local_ns()` is +equivalent of calling `odp_time_to_ns(odp_time_local())`. This simplifies use +cases where time will be always converted to nanoseconds. However, when time API +performance is important conversions to nanoseconds should be avoided or +minimized. + +==== Timer +* Clarify that `odp_timeout_tick()` returns original expiration time + +Specification was open if returned expiration time is the original or actual +expiration time. HW based implementations will not likely modify timeout event +with actual expiration time. Also original expiration time is more valuable to +an application as it can be used to calculate e.g. the next period. + +* Add resolution in hertz parameter `res_hz` into `odp_timer_pool_param_t` + +Added option to specify timer pool resolution in hertz. High resolution values +in nanoseconds result small numbers and thus poor granularity. Hertz offers +better granularity with high resolution values. User gives resolution either in +nanoseconds or hertz, and sets the other parameter to zero. + +==== Traffic Manager +* Add missing handle debug functions + +Traffic Manager API defines all types as platform specific, yet unit tests +expect to be able to print them. Therefore introduce u64 debug print conversion +functions for all TM types: `odp_tm_to_u64()`, `odp_tm_queue_to_u64()`, +`odp_tm_node_to_u64()`, `odp_tm_shaper_to_u64()`, `odp_tm_sched_to_u64()`, +`odp_tm_threshold_to_u64()`, `odp_tm_wred_to_u64()` + +* Info structures are written only on success + +Clarify that info structures (`odp_tm_node_info_t`, `odp_tm_node_fanin_info_t`, +`odp_tm_queue_info_t`, `odp_tm_query_info_t`) are written only on success. + +==== Version +* Added `ODP_VERSION_API` define and `ODP_VERSION_API_NUM` macro + +Added a macro and version number defines for easier comparison of API version +numbers. + +=== Validation Tests +==== Buffer +* Rewrote buffer tests for improved coverage +* Allow allocated buffer size to be larger than requested + +==== Classification +* Fix duplicate global variable definition +* Use `odp_schedule_wait_time()` correctly + +==== Crypto +* Fix var len array scope + +==== Init +* Add tests for new `compress` and `stash` feature bits +* Improved log prints + +==== IPSec +* Fixed invalid allocation of zero length test packet +* Fixed invalid test for user pointer value + +==== Packet +* Add max pools test +* Add packet alloc align test +* Fix max_num expectations +* Prevent test trying to allocate zero length packets +* Remove pools from suite init +* Remove reset test packet from suite init +* Rename default pool +* Use common pool capability + +==== Packet I/O +* Check parser flags on receive +* Check pktio index +* Decrease timeout in `odp_pktin_recv_tmo()` test +* Make `pktio_check_start_stop()` test conditional +* Remove unnecessary test start-up input flushes +* Test `odp_packet_input_set()` +* Test user pointer on receive +* Do no attempt to continue with invalid queue handle + +==== Pool +* Add pool cache size tests +* Add test for packet pool seg_len parameter + +==== Queue +* Lockfree queue max_size may be zero + +==== Scheduler +* Add new stress test +* Fix plain+sched test +* Test `odp_schedule_group_create()` with non-zero mask + +==== Shared Memory +* Add reserve flag tests +* Fix printf format types for pointers + +==== Stash +* Add tests for the new API + +==== System +* Add test for `ODP_CACHE_LINE_ROUNDUP` +* Add version macro test +* Call version string functions +* Cpu cycle counter may not be supported +* Make `odp_cpu_hz_max()` tests conditional + +==== Timer +* Timeout tick equals requested tick +* Always initialize `odp_timer_pool_param_t` contents + +==== Traffic Manager +* Fix shaper profile parameter check +* Init structs between tests + +=== Example Applications +==== Bench_packet +* Added tests for missing packet functions + +==== Hello +* Removed `-c` command line option + +==== L2fwd +* Added number of packets option `-n` +* Added packet copy option `-p` +* Added pool per interface option `-y` + +==== Packet_dump +* Added VLAN support + +==== Packet_gen +* Added new simple packet generator test application + +==== Sched_latency +* Added option for selecting event forwarding mode `-f` +* Increased the number of warm-up and scheduling rounds + +==== Sched_perf +* Added data touch options `-n` and `-m` +* Added queue context data touch options `-k` and `-l` +* Improved test reliability + +==== Switch +* Added 5 minute aging time to MAC table entries +* Added signal handler for SIGINT +* Added support for detecting invalid and broadcast ethernet addresses +* Improved packet drop statistics printing + +==== Timer_accuracy +* Added burst gap option `-g` +* Added mode option `-m` +* Added option `-e` to retry on too early error +* Added output file option `-o` +* Added timer burst option `-b` + +=== Implementation Improvements +==== GCC 10 support +Fixed issues reported by GCC 10. The code base builds now with GCC 10 +also when LTO is enabled. + +==== Add configure option for setting path to the default config file +Added `--with-config-file=FILE` configuration option for setting path to the +default configuration file. The default configuration file has to include all +configuration options. + +=== Bug Fixes +==== Numbered Bugs / Issues +* Fixed: https://github.com/OpenDataPlane/odp/issues/796[Issue 796] +seg[0].data MUST return to its initial value on odp_packet_reset + +* Fixed: https://github.com/OpenDataPlane/odp/issues/826[Issue 826] +max_size requires clarification for ODP_NONBLOCKING_LF and ODP_NONBLOCKING_WF + +* Fixed: https://github.com/OpenDataPlane/odp/issues/915[Issue 915] +SIGSEGV: example/sysinfo (raspberry Pi 3B+, arm7, odp-linux, gcc 8.2.0) + +* Fixed: https://github.com/OpenDataPlane/odp/issues/930[Issue 930] +Build failing with GCC 9.2 + +* Fixed: https://github.com/OpenDataPlane/odp/issues/959[Issue 959] +ODP build fails with GCC 10.1 + +==== Unnumbered Bugs / Issues +* Fixed: crypto: fix session allocation when out of sessions +* Fixed: dpdk: DPDK renamed protocol structs +* Fixed: dpdk: fix rx/tx checksum offload +* Fixed: fix print failures on 32-bit systems +* Fixed: pool: fix overflow when creating a huge packet pool +* Fixed: pool: rename pool global variable +* Fixed: sched scalable: fix pktio ingress queue polling dead lock +* Fixed: test: fix global variables that are defined multiple times +* Fixed: timer: fix timer pool create sync with inline timer scan + == OpenDataPlane (1.23.0.0) === Summary of Changes The ODP API changes in this release are related to the classifier module. @@ -1,7 +1,7 @@ #! /bin/sh set -x aclocal -I config -I m4 -libtoolize --copy +libtoolize --copy --force autoheader automake --add-missing --copy --warnings=all autoconf --force diff --git a/configure.ac b/configure.ac index b12001f25..465304d9e 100644 --- a/configure.ac +++ b/configure.ac @@ -3,8 +3,8 @@ AC_PREREQ([2.5]) # ODP API version ########################################################################## m4_define([odpapi_generation_version], [1]) -m4_define([odpapi_major_version], [23]) -m4_define([odpapi_minor_version], [5]) +m4_define([odpapi_major_version], [24]) +m4_define([odpapi_minor_version], [0]) m4_define([odpapi_point_version], [0]) m4_define([odpapi_version], [odpapi_generation_version.odpapi_major_version.odpapi_minor_version.odpapi_point_version]) @@ -136,7 +136,7 @@ ODP_CHECK_CFLAG([-Wno-error=address-of-packed-member]) # GCC 10 sometimes gets confused about object sizes and gives bogus warnings. # Make the affected warnings generate only warnings, not errors. AS_IF([test "$GCC" == yes], - AS_IF([test `$CC -dumpversion` -ge 10], + AS_IF([test `$CC -dumpversion | cut -d '.' -f 1` -ge 10], ODP_CHECK_CFLAG([-Wno-error=array-bounds]) ODP_CHECK_CFLAG([-Wno-error=stringop-overflow]) ) @@ -295,6 +295,7 @@ AC_DEFINE_UNQUOTED([_ODP_IMPLEMENTATION_NAME], ["$ODP_IMPLEMENTATION_NAME"], [Define to the name of the implementation]) AM_CONDITIONAL([ODP_USE_CONFIG], [test "x$odp_use_config" = "xtrue"]) +AC_SUBST([ODP_LIB_NAME]) ########################################################################## # Build examples/tests dynamically @@ -456,6 +457,7 @@ AC_OUTPUT AC_MSG_RESULT([ $PACKAGE $VERSION + ODP Library name: ${ODP_LIB_NAME} ODP Library version: ${ODP_LIBSO_VERSION} Helper Library version: ${ODPHELPER_LIBSO_VERSION} @@ -499,6 +501,7 @@ AC_MSG_RESULT([ test_example: ${test_example} user_guides: ${user_guides} pcapng: ${have_pcapng} + default_config_path: ${default_config_path} ]) AS_IF([test "${with_openssl}" = "no"], diff --git a/example/Makefile.inc b/example/Makefile.inc index 4668b0ae7..4330431af 100644 --- a/example/Makefile.inc +++ b/example/Makefile.inc @@ -4,7 +4,7 @@ include $(top_srcdir)/Makefile.inc TESTS_ENVIRONMENT = EXEEXT=${EXEEXT} -LDADD = $(LIB)/libodp-linux.la $(LIB)/libodphelper.la +LDADD = $(LIB)/libodphelper.la $(LIB)/lib$(ODP_LIB_NAME).la # Do not link to DPDK twice in case of dynamic linking with ODP if STATIC_APPS diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c index a50468d6e..2db4c9158 100644 --- a/example/ipsec/odp_ipsec.c +++ b/example/ipsec/odp_ipsec.c @@ -1326,6 +1326,10 @@ main(int argc, char *argv[]) /* If we have test streams build them before starting workers */ resolve_stream_db(); stream_count = create_stream_db_inputs(); + if (stream_count < 0) { + ODPH_ERR("Error: creating input packets failed\n"); + exit(EXIT_FAILURE); + } /* * Create and init worker threads @@ -1632,6 +1636,7 @@ static void usage(char *progname) "\n" "Optional OPTIONS\n" " -c, --count <number> CPU count, 0=all available, default=1\n" + " -s, --stream SrcIP:DstIP:InIntf:OutIntf:Count:Length\n" " -h, --help Display help and exit.\n" " environment variables: ODP_IPSEC_USE_POLL_QUEUES\n" " to enable use of poll queues instead of scheduled (default)\n" diff --git a/example/ipsec/odp_ipsec_stream.c b/example/ipsec/odp_ipsec_stream.c index 9f953e4a9..d689c6198 100644 --- a/example/ipsec/odp_ipsec_stream.c +++ b/example/ipsec/odp_ipsec_stream.c @@ -168,7 +168,8 @@ void resolve_stream_db(void) odp_packet_t create_ipv4_packet(stream_db_entry_t *stream, uint8_t *dmac, - odp_pool_t pkt_pool) + odp_pool_t pkt_pool, + uint32_t max_len) { ipsec_cache_entry_t *entry = NULL; odp_packet_t pkt; @@ -188,10 +189,18 @@ odp_packet_t create_ipv4_packet(stream_db_entry_t *stream, else if (stream->output.entry) entry = stream->output.entry; + /* Make sure there is enough space for protocol overhead */ + if ((stream->length + 200) > max_len) { + ODPH_ERR("Error: too large test packet\n"); + return ODP_PACKET_INVALID; + } + /* Get packet */ - pkt = odp_packet_alloc(pkt_pool, 0); - if (ODP_PACKET_INVALID == pkt) + pkt = odp_packet_alloc(pkt_pool, max_len); + if (ODP_PACKET_INVALID == pkt) { + ODPH_ERR("Error: packet alloc failed\n"); return ODP_PACKET_INVALID; + } base = odp_packet_data(pkt); data = odp_packet_data(pkt); @@ -358,7 +367,7 @@ odp_packet_t create_ipv4_packet(stream_db_entry_t *stream, } /* Correct set packet length offsets */ - odp_packet_push_tail(pkt, data - base); + odp_packet_pull_tail(pkt, max_len - (data - base)); odp_packet_l2_offset_set(pkt, (uint8_t *)eth - base); odp_packet_l3_offset_set(pkt, (uint8_t *)ip - base); odp_packet_l4_offset_set(pkt, ((uint8_t *)ip - base) + sizeof(*ip)); @@ -545,14 +554,23 @@ int create_stream_db_inputs(void) { int created = 0; odp_pool_t pkt_pool; + odp_pool_info_t pool_info; stream_db_entry_t *stream = NULL; + uint32_t max_len; /* Lookup the packet pool */ pkt_pool = odp_pool_lookup("packet_pool"); if (pkt_pool == ODP_POOL_INVALID) { ODPH_ERR("Error: pkt_pool not found\n"); - exit(EXIT_FAILURE); + return -1; } + if (odp_pool_info(pkt_pool, &pool_info)) { + ODPH_ERR("Error: pool info failed\n"); + return -1; + } + + /* Only single segment packets are supported */ + max_len = pool_info.params.pkt.seg_len; /* For each stream create corresponding input packets */ for (stream = stream_db->list; NULL != stream; stream = stream->next) { @@ -579,15 +597,15 @@ int create_stream_db_inputs(void) for (count = stream->count; count > 0; count--) { odp_packet_t pkt; - pkt = create_ipv4_packet(stream, dmac, pkt_pool); + pkt = create_ipv4_packet(stream, dmac, pkt_pool, max_len); if (ODP_PACKET_INVALID == pkt) { - printf("Packet buffers exhausted\n"); + ODPH_ERR("Error: packet buffers exhausted\n"); break; } stream->created++; if (odp_pktout_send(queue, &pkt, 1) != 1) { odp_packet_free(pkt); - printf("Queue enqueue failed\n"); + ODPH_ERR("Error: queue enqueue failed\n"); break; } @@ -596,6 +614,10 @@ int create_stream_db_inputs(void) created++; } } + if ((stream_db->index > 0) && created == 0) { + ODPH_ERR("Error: failed to create any input streams\n"); + return -1; + } return created; } diff --git a/example/ipsec/odp_ipsec_stream.h b/example/ipsec/odp_ipsec_stream.h index 91ccb0be2..b32f1d7cb 100644 --- a/example/ipsec/odp_ipsec_stream.h +++ b/example/ipsec/odp_ipsec_stream.h @@ -85,12 +85,14 @@ void resolve_stream_db(void); * @param stream Stream DB entry * @param dmac Destination MAC address to use * @param pkt_pool Packet buffer pool to allocate from + * @param max_len Maximum packet length * * @return packet else ODP_PACKET_INVALID */ odp_packet_t create_ipv4_packet(stream_db_entry_t *stream, uint8_t *dmac, - odp_pool_t pkt_pool); + odp_pool_t pkt_pool, + uint32_t max_len); /** * Verify an IPv4 packet received on a loop output queue @@ -108,10 +110,11 @@ odp_bool_t verify_ipv4_packet(stream_db_entry_t *stream, * * Create input packets based on the configured streams and enqueue them * into loop interface input queues. Once packet processing starts these - * packets will be remomved and processed as if they had come from a normal + * packets will be removed and processed as if they had come from a normal * packet interface. * * @return number of streams successfully processed + * @return <0 on failure */ int create_stream_db_inputs(void); diff --git a/example/ipsec_api/odp_ipsec.c b/example/ipsec_api/odp_ipsec.c index a02343467..c7ae1be4e 100644 --- a/example/ipsec_api/odp_ipsec.c +++ b/example/ipsec_api/odp_ipsec.c @@ -1020,6 +1020,10 @@ main(int argc, char *argv[]) /* If we have test streams build them before starting workers */ resolve_stream_db(); stream_count = create_stream_db_inputs(); + if (stream_count < 0) { + ODPH_ERR("Error: creating input packets failed\n"); + exit(EXIT_FAILURE); + } /* * Create and init worker threads @@ -1331,6 +1335,7 @@ static void usage(char *progname) "\n" "Optional OPTIONS\n" " -c, --count <number> CPU count, 0=all available, default=1\n" + " -s, --stream SrcIP:DstIP:InIntf:OutIntf:Count:Length\n" " -h, --help Display help and exit.\n" " environment variables: ODP_IPSEC_USE_POLL_QUEUES\n" " to enable use of poll queues instead of scheduled (default)\n" diff --git a/example/l2fwd_simple/odp_l2fwd_simple.c b/example/l2fwd_simple/odp_l2fwd_simple.c index 48f1462dd..94f21ddf2 100644 --- a/example/l2fwd_simple/odp_l2fwd_simple.c +++ b/example/l2fwd_simple/odp_l2fwd_simple.c @@ -23,7 +23,7 @@ typedef struct { odp_pktout_queue_t if0out, if1out; odph_ethaddr_t src, dst; odp_shm_t shm; - int exit_thr; + odp_atomic_u32_t exit_thr; int wait_sec; } global_data_t; @@ -34,7 +34,7 @@ static void sig_handler(int signo ODP_UNUSED) printf("sig_handler!\n"); if (global == NULL) return; - global->exit_thr = 1; + odp_atomic_store_u32(&global->exit_thr, 1); } static odp_pktio_t create_pktio(const char *name, odp_pool_t pool, @@ -105,7 +105,7 @@ static int run_worker(void *arg ODP_UNUSED) printf("started output interface\n"); printf("started all\n"); - while (!global->exit_thr) { + while (!odp_atomic_load_u32(&global->exit_thr)) { pkts = odp_pktin_recv_tmo(global->if0in, pkt_tbl, MAX_PKT_BURST, wait_time); @@ -189,6 +189,7 @@ int main(int argc, char **argv) } memset(global, 0, sizeof(global_data_t)); + odp_atomic_init_u32(&global->exit_thr, 0); global->shm = shm; if (argc > 7 || diff --git a/example/l3fwd/odp_l3fwd.c b/example/l3fwd/odp_l3fwd.c index 0f8b8525c..eda63881f 100644 --- a/example/l3fwd/odp_l3fwd.c +++ b/example/l3fwd/odp_l3fwd.c @@ -66,7 +66,8 @@ struct thread_arg_s { }; typedef struct { - char *if_names[MAX_NB_PKTIO]; + char *if_names_buf; /* memory buffer for all if_names */ + char *if_names[MAX_NB_PKTIO]; /* pointers to name strings stored in if_names_buf */ int if_count; char *route_str[MAX_NB_ROUTE]; unsigned int worker_count; @@ -89,7 +90,7 @@ typedef struct { /** Shm for storing global data */ odp_shm_t shm; /** Break workers loop if set to 1 */ - int exit_threads; + odp_atomic_u32_t exit_threads; /* forward func, hash or lpm */ int (*fwd_func)(odp_packet_t pkt, int sif); @@ -322,7 +323,7 @@ static int run_worker(void *arg) odp_barrier_wait(&global->barrier); - while (!global->exit_threads) { + while (!odp_atomic_load_u32(&global->exit_threads)) { if (num_pktio > 1) { if_idx = input_ifs[pktio]; inq = input_queues[pktio]; @@ -570,30 +571,25 @@ static void parse_cmdline_args(int argc, char *argv[], app_args_t *args) print_usage(argv[0]); exit(EXIT_FAILURE); } + args->if_names_buf = local; - /* count the number of tokens separated by ',' */ + /* store the if names (reset names string) */ strcpy(local, optarg); for (token = strtok(local, ","), i = 0; - token != NULL; - token = strtok(NULL, ","), i++) - ; - + token != NULL; token = strtok(NULL, ","), i++) { + if (i >= MAX_NB_PKTIO) { + printf("too many ports specified, " + "truncated to %d", MAX_NB_PKTIO); + break; /* for */ + } + args->if_names[i] = token; + } if (i == 0) { print_usage(argv[0]); free(local); exit(EXIT_FAILURE); - } else if (i > MAX_NB_PKTIO) { - printf("too many ports specified, " - "truncated to %d", MAX_NB_PKTIO); } args->if_count = i; - - /* store the if names (reset names string) */ - strcpy(local, optarg); - for (token = strtok(local, ","), i = 0; - token != NULL; token = strtok(NULL, ","), i++) { - args->if_names[i] = token; - } break; /*Configure Route in forwarding database*/ @@ -976,6 +972,7 @@ int main(int argc, char **argv) } memset(global, 0, sizeof(global_data_t)); + odp_atomic_init_u32(&global->exit_threads, 0); global->shm = shm; /* Initialize the dest mac as 2:0:0:0:0:x */ @@ -1121,7 +1118,7 @@ int main(int argc, char **argv) } print_speed_stats(nb_worker, args->duration, PRINT_INTERVAL); - global->exit_threads = 1; + odp_atomic_store_u32(&global->exit_threads, 1); /* wait for other threads to join */ for (i = 0; i < nb_worker; i++) @@ -1137,8 +1134,8 @@ int main(int argc, char **argv) } } - /* if_names share a single buffer, so only one free */ - free(args->if_names[0]); + /* if_names share a single buffer */ + free(args->if_names_buf); for (i = 0; i < MAX_NB_ROUTE; i++) free(args->route_str[i]); diff --git a/example/packet/odp_packet_dump.c b/example/packet/odp_packet_dump.c index e1ef7e14d..04d6576c5 100644 --- a/example/packet/odp_packet_dump.c +++ b/example/packet/odp_packet_dump.c @@ -36,7 +36,7 @@ typedef struct test_options_t { typedef struct test_global_t { test_options_t opt; odp_pool_t pool; - int stop; + odp_atomic_u32_t stop; struct { odp_pktio_t pktio; @@ -52,8 +52,7 @@ static void sig_handler(int signo) { (void)signo; - test_global.stop = 1; - odp_mb_full(); + odp_atomic_store_u32(&test_global.stop, 1); } static void print_usage(void) @@ -636,7 +635,7 @@ static int receive_packets(test_global_t *global) int printed; uint64_t num_packet = 0; - while (!global->stop) { + while (!odp_atomic_load_u32(&global->stop)) { ev = odp_schedule(NULL, ODP_SCHED_NO_WAIT); if (ev == ODP_EVENT_INVALID) @@ -674,6 +673,7 @@ int main(int argc, char *argv[]) global = &test_global; memset(global, 0, sizeof(test_global_t)); + odp_atomic_init_u32(&global->stop, 0); signal(SIGINT, sig_handler); diff --git a/example/packet/odp_pktio.c b/example/packet/odp_pktio.c index 24aa039d5..6065bcc88 100644 --- a/example/packet/odp_pktio.c +++ b/example/packet/odp_pktio.c @@ -88,7 +88,7 @@ typedef struct { /** Thread specific arguments */ thread_args_t thread[MAX_WORKERS]; /** Flag to exit worker threads */ - int exit_threads; + odp_atomic_u32_t exit_threads; } args_t; /** Global pointer to args */ @@ -206,7 +206,7 @@ static int pktio_queue_thread(void *arg) } /* Loop packets */ - while (!args->exit_threads) { + while (!odp_atomic_load_u32(&args->exit_threads)) { odp_pktio_t pktio_tmp; if (inq != ODP_QUEUE_INVALID) @@ -296,7 +296,7 @@ static int pktio_ifburst_thread(void *arg) } /* Loop packets */ - while (!args->exit_threads) { + while (!odp_atomic_load_u32(&args->exit_threads)) { pkts = odp_pktin_recv(pktin, pkt_tbl, MAX_PKT_BURST); if (pkts > 0) { /* Drop packets with errors */ @@ -392,6 +392,7 @@ int main(int argc, char *argv[]) } memset(args, 0, sizeof(args_t)); + odp_atomic_init_u32(&args->exit_threads, 0); args->shm = shm; /* Parse and store the application arguments */ @@ -482,7 +483,7 @@ int main(int argc, char *argv[]) } /* use delay to let workers clean up queues */ odp_time_wait_ns(ODP_TIME_SEC_IN_NS); - args->exit_threads = 1; + odp_atomic_store_u32(&args->exit_threads, 1); } /* Master thread waits for other threads to exit */ diff --git a/example/ping/odp_ping.c b/example/ping/odp_ping.c index 750f3a9e3..ec5746bcf 100644 --- a/example/ping/odp_ping.c +++ b/example/ping/odp_ping.c @@ -32,7 +32,7 @@ typedef struct test_global_t { uint64_t rx_packets; uint64_t tx_replies; odp_pool_t pool; - int stop; + odp_atomic_u32_t stop; struct { odph_ethaddr_t eth_addr; @@ -50,8 +50,7 @@ static void sig_handler(int signo) { (void)signo; - test_global.stop = 1; - odp_mb_full(); + odp_atomic_store_u32(&test_global.stop, 1); } static void print_usage(void) @@ -408,11 +407,12 @@ static void print_packet(odp_packet_t pkt, uint64_t num_packet) nsec = nsec - (sec * ODP_TIME_SEC_IN_NS); pktio = odp_packet_input(pkt); - odp_pktio_info(pktio, &pktio_info); - printf("PACKET [%" PRIu64 "]\n", num_packet); printf(" time: %" PRIu64 ".%09" PRIu64 " sec\n", sec, nsec); - printf(" interface name: %s\n", pktio_info.name); + if (odp_pktio_info(pktio, &pktio_info) == 0) + printf(" interface name: %s\n", pktio_info.name); + else + printf(" interface name: n/a\n"); printf(" packet length: %u bytes\n", odp_packet_len(pkt)); /* L2 */ @@ -575,7 +575,7 @@ static int receive_packets(test_global_t *global) odp_time_t cur = odp_time_local(); odp_time_t prev = cur; - while (!global->stop) { + while (!odp_atomic_load_u32(&global->stop)) { ev = odp_schedule(NULL, wait); cur = odp_time_local(); @@ -629,6 +629,7 @@ int main(int argc, char *argv[]) global = &test_global; memset(global, 0, sizeof(test_global_t)); + odp_atomic_init_u32(&global->stop, 0); signal(SIGINT, sig_handler); diff --git a/example/simple_pipeline/odp_simple_pipeline.c b/example/simple_pipeline/odp_simple_pipeline.c index 9beb8a78d..b01efee84 100644 --- a/example/simple_pipeline/odp_simple_pipeline.c +++ b/example/simple_pipeline/odp_simple_pipeline.c @@ -74,7 +74,7 @@ typedef struct { odp_pktout_queue_t if0out, if1out; odph_ethaddr_t src_addr; /* Source MAC address */ odph_ethaddr_t dst_addr; /* Destination MAC address */ - int exit_threads; + odp_atomic_u32_t exit_threads; /* Application (parsed) arguments */ appl_args_t appl; } global_data_t; @@ -83,7 +83,7 @@ static global_data_t *global; static void sig_handler(int signo ODP_UNUSED) { - global->exit_threads = 1; + odp_atomic_store_u32(&global->exit_threads, 1); } static odp_pktio_t create_pktio(const char *name, odp_pool_t pool, @@ -191,7 +191,7 @@ static inline int rx_thread(void *arg) odp_barrier_wait(&global->init_barrier); - while (!global->exit_threads) { + while (!odp_atomic_load_u32(&global->exit_threads)) { pkts = odp_pktin_recv(pktin_queue, pkt_tbl, MAX_PKT_BURST); if (odp_unlikely(pkts <= 0)) continue; @@ -234,7 +234,7 @@ static inline int tx_thread(void *arg) odp_barrier_wait(&global->init_barrier); - while (!global->exit_threads) { + while (!odp_atomic_load_u32(&global->exit_threads)) { events = odp_queue_deq_multi(rx_queue, event_tbl, MAX_PKT_BURST); if (odp_unlikely(events <= 0)) @@ -301,7 +301,7 @@ static inline int worker_thread(void *arg ODP_UNUSED) odp_barrier_wait(&global->init_barrier); - while (!global->exit_threads) { + while (!odp_atomic_load_u32(&global->exit_threads)) { events = odp_queue_deq_multi(rx_queue, event_tbl, MAX_PKT_BURST); @@ -472,7 +472,7 @@ static int print_speed_stats(int num_workers, stats_t **thr_stats, pkts_prev = total_pkts; } elapsed += timeout; - } while (!global->exit_threads && (loop_forever || + } while (!odp_atomic_load_u32(&global->exit_threads) && (loop_forever || (elapsed < duration))); if (stats_enabled) @@ -736,6 +736,7 @@ int main(int argc, char **argv) } memset(global, 0, sizeof(global_data_t)); + odp_atomic_init_u32(&global->exit_threads, 0); signal(SIGINT, sig_handler); @@ -905,7 +906,7 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - global->exit_threads = 1; + odp_atomic_store_u32(&global->exit_threads, 1); odp_barrier_wait(&global->term_barrier); odph_thread_join(thr_tbl, num_threads); diff --git a/example/switch/odp_switch.c b/example/switch/odp_switch.c index bcc87680e..989016fc8 100644 --- a/example/switch/odp_switch.c +++ b/example/switch/odp_switch.c @@ -131,7 +131,7 @@ typedef struct { /** Global barrier to synchronize main and workers */ odp_barrier_t barrier; /** Break workers loop if set to 1 */ - int exit_threads; + odp_atomic_u32_t exit_threads; /** Table of pktio handles */ struct { odp_pktio_t pktio; @@ -154,7 +154,7 @@ static void sig_handler(int signo ODP_UNUSED) { if (gbl_args == NULL) return; - gbl_args->exit_threads = 1; + odp_atomic_store_u32(&gbl_args->exit_threads, 1); } /** @@ -424,7 +424,7 @@ static int print_speed_stats(int num_workers, stats_t (*thr_stats)[MAX_PKTIOS], PRIu64 " rx drops, %" PRIu64 " tx drops\n", rx_pkts_tot, tx_pkts_tot, rx_drops_tot, tx_drops_tot); - } while (!gbl_args->exit_threads && + } while (!odp_atomic_load_u32(&gbl_args->exit_threads) && (loop_forever || (elapsed < duration))); return rx_pkts_tot >= 100 ? 0 : -1; @@ -686,7 +686,7 @@ static int run_worker(void *arg) time_prev = odp_time_local(); cur_tick = (odp_time_to_ns(time_prev) / ODP_TIME_MIN_IN_NS) % UINT8_MAX; - while (!gbl_args->exit_threads) { + while (!odp_atomic_load_u32(&gbl_args->exit_threads)) { odp_time_t time_cur; odp_time_t time_diff; int sent; @@ -962,6 +962,7 @@ static void gbl_args_init(args_t *args) int pktio; memset(args, 0, sizeof(args_t)); + odp_atomic_init_u32(&args->exit_threads, 0); for (pktio = 0; pktio < MAX_PKTIOS; pktio++) args->pktios[pktio].pktio = ODP_PKTIO_INVALID; @@ -1132,7 +1133,7 @@ int main(int argc, char **argv) ret = print_speed_stats(num_workers, gbl_args->stats, gbl_args->appl.time, gbl_args->appl.accuracy); - gbl_args->exit_threads = 1; + odp_atomic_store_u32(&gbl_args->exit_threads, 1); /* Master thread waits for other threads to exit */ for (i = 0; i < num_workers; ++i) diff --git a/example/timer/odp_timer_accuracy.c b/example/timer/odp_timer_accuracy.c index dccf70326..7208f216c 100644 --- a/example/timer/odp_timer_accuracy.c +++ b/example/timer/odp_timer_accuracy.c @@ -721,7 +721,7 @@ quit: if (test_global.file) fclose(test_global.file); - if (destroy_timers(&test_global)) + if (test_global.timer_ctx && destroy_timers(&test_global)) ret = -1; if (test_global.timer_ctx) diff --git a/example/timer/odp_timer_simple.c b/example/timer/odp_timer_simple.c index 8084a4568..efbdf7673 100644 --- a/example/timer/odp_timer_simple.c +++ b/example/timer/odp_timer_simple.c @@ -69,6 +69,7 @@ int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED) ret += 1; goto err_tp; } + memset(&tparams, 0, sizeof(tparams)); tparams.res_ns = MAX(10 * ODP_TIME_MSEC_IN_NS, timer_capa.highest_res_ns); tparams.min_tmo = 10 * ODP_TIME_MSEC_IN_NS; diff --git a/helper/Makefile.am b/helper/Makefile.am index 762f80602..8347ff96d 100644 --- a/helper/Makefile.am +++ b/helper/Makefile.am @@ -62,6 +62,6 @@ __LIB__libodphelper_la_SOURCES += \ linux/thread.c endif -__LIB__libodphelper_la_LIBADD = $(PTHREAD_LIBS) $(LIB)/libodp-linux.la +__LIB__libodphelper_la_LIBADD = $(PTHREAD_LIBS) lib_LTLIBRARIES = $(LIB)/libodphelper.la diff --git a/helper/cuckootable.c b/helper/cuckootable.c index 237c2f297..47dd90b6c 100644 --- a/helper/cuckootable.c +++ b/helper/cuckootable.c @@ -260,7 +260,11 @@ odph_cuckoo_table_create( pool = odp_pool_lookup(pool_name); if (pool != ODP_POOL_INVALID) - odp_pool_destroy(pool); + if (odp_pool_destroy(pool)) { + odp_shm_free(shm_tbl); + ODPH_DBG("failed to destroy pre-existing pool\n"); + return NULL; + } odp_pool_param_init(¶m); param.type = ODP_POOL_BUFFER; @@ -285,7 +289,7 @@ odph_cuckoo_table_create( queue = odp_queue_create(queue_name, &qparam); if (queue == ODP_QUEUE_INVALID) { ODPH_DBG("failed to create free_slots queue\n"); - odp_pool_destroy(pool); + (void)odp_pool_destroy(pool); odp_shm_free(shm_tbl); return NULL; } diff --git a/helper/iplookuptable.c b/helper/iplookuptable.c index c02ee5415..eacfcf5f8 100644 --- a/helper/iplookuptable.c +++ b/helper/iplookuptable.c @@ -150,7 +150,7 @@ cache_destroy(odph_iplookup_table_impl *impl) sprintf( pool_name, "%s_%d_%d", impl->name, i, count); - odp_pool_destroy(odp_pool_lookup(pool_name)); + (void)odp_pool_destroy(odp_pool_lookup(pool_name)); } } } diff --git a/include/Makefile.am b/include/Makefile.am index b779e9ad4..32d8a6825 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -127,7 +127,9 @@ odpapiabidefaultinclude_HEADERS = \ odp/api/abi-default/cpumask.h \ odp/api/abi-default/crypto.h \ odp/api/abi-default/debug.h \ + odp/api/abi-default/errno.h \ odp/api/abi-default/event.h \ + odp/api/abi-default/hash.h \ odp/api/abi-default/init.h \ odp/api/abi-default/ipsec.h \ odp/api/abi-default/packet.h \ @@ -171,7 +173,9 @@ odpapiabiarchinclude_HEADERS = \ odp/arch/arm32-linux/odp/api/abi/cpumask.h \ odp/arch/arm32-linux/odp/api/abi/crypto.h \ odp/arch/arm32-linux/odp/api/abi/debug.h \ + odp/arch/arm32-linux/odp/api/abi/errno.h \ odp/arch/arm32-linux/odp/api/abi/event.h \ + odp/arch/arm32-linux/odp/api/abi/hash.h \ odp/arch/arm32-linux/odp/api/abi/init.h \ odp/arch/arm32-linux/odp/api/abi/ipsec.h \ odp/arch/arm32-linux/odp/api/abi/packet.h \ @@ -211,7 +215,9 @@ odpapiabiarchinclude_HEADERS = \ odp/arch/arm64-linux/odp/api/abi/cpumask.h \ odp/arch/arm64-linux/odp/api/abi/crypto.h \ odp/arch/arm64-linux/odp/api/abi/debug.h \ + odp/arch/arm64-linux/odp/api/abi/errno.h \ odp/arch/arm64-linux/odp/api/abi/event.h \ + odp/arch/arm64-linux/odp/api/abi/hash.h \ odp/arch/arm64-linux/odp/api/abi/init.h \ odp/arch/arm64-linux/odp/api/abi/ipsec.h \ odp/arch/arm64-linux/odp/api/abi/packet.h \ @@ -251,7 +257,9 @@ odpapiabiarchinclude_HEADERS = \ odp/arch/default-linux/odp/api/abi/cpumask.h \ odp/arch/default-linux/odp/api/abi/crypto.h \ odp/arch/default-linux/odp/api/abi/debug.h \ + odp/arch/default-linux/odp/api/abi/errno.h \ odp/arch/default-linux/odp/api/abi/event.h \ + odp/arch/default-linux/odp/api/abi/hash.h \ odp/arch/default-linux/odp/api/abi/init.h \ odp/arch/default-linux/odp/api/abi/ipsec.h \ odp/arch/default-linux/odp/api/abi/packet.h \ @@ -291,7 +299,9 @@ odpapiabiarchinclude_HEADERS = \ odp/arch/mips64-linux/odp/api/abi/cpumask.h \ odp/arch/mips64-linux/odp/api/abi/crypto.h \ odp/arch/mips64-linux/odp/api/abi/debug.h \ + odp/arch/mips64-linux/odp/api/abi/errno.h \ odp/arch/mips64-linux/odp/api/abi/event.h \ + odp/arch/mips64-linux/odp/api/abi/hash.h \ odp/arch/mips64-linux/odp/api/abi/init.h \ odp/arch/mips64-linux/odp/api/abi/ipsec.h \ odp/arch/mips64-linux/odp/api/abi/packet.h \ @@ -331,7 +341,9 @@ odpapiabiarchinclude_HEADERS = \ odp/arch/power64-linux/odp/api/abi/cpumask.h \ odp/arch/power64-linux/odp/api/abi/crypto.h \ odp/arch/power64-linux/odp/api/abi/debug.h \ + odp/arch/power64-linux/odp/api/abi/errno.h \ odp/arch/power64-linux/odp/api/abi/event.h \ + odp/arch/power64-linux/odp/api/abi/hash.h \ odp/arch/power64-linux/odp/api/abi/init.h \ odp/arch/power64-linux/odp/api/abi/ipsec.h \ odp/arch/power64-linux/odp/api/abi/packet.h \ @@ -371,7 +383,9 @@ odpapiabiarchinclude_HEADERS = \ odp/arch/x86_32-linux/odp/api/abi/cpumask.h \ odp/arch/x86_32-linux/odp/api/abi/crypto.h \ odp/arch/x86_32-linux/odp/api/abi/debug.h \ + odp/arch/x86_32-linux/odp/api/abi/errno.h \ odp/arch/x86_32-linux/odp/api/abi/event.h \ + odp/arch/x86_32-linux/odp/api/abi/hash.h \ odp/arch/x86_32-linux/odp/api/abi/init.h \ odp/arch/x86_32-linux/odp/api/abi/ipsec.h \ odp/arch/x86_32-linux/odp/api/abi/packet.h \ @@ -411,7 +425,9 @@ odpapiabiarchinclude_HEADERS = \ odp/arch/x86_64-linux/odp/api/abi/cpumask.h \ odp/arch/x86_64-linux/odp/api/abi/crypto.h \ odp/arch/x86_64-linux/odp/api/abi/debug.h \ + odp/arch/x86_64-linux/odp/api/abi/errno.h \ odp/arch/x86_64-linux/odp/api/abi/event.h \ + odp/arch/x86_64-linux/odp/api/abi/hash.h \ odp/arch/x86_64-linux/odp/api/abi/init.h \ odp/arch/x86_64-linux/odp/api/abi/ipsec.h \ odp/arch/x86_64-linux/odp/api/abi/packet.h \ diff --git a/include/odp/api/abi-default/errno.h b/include/odp/api/abi-default/errno.h new file mode 100644 index 000000000..6437930a0 --- /dev/null +++ b/include/odp/api/abi-default/errno.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * ODP errno + */ + +#ifndef ODP_ABI_ERRNO_H_ +#define ODP_ABI_ERRNO_H_ + +/* Empty header to allow platforms to override inlining + * of errno functions. + */ + +#endif diff --git a/include/odp/api/abi-default/hash.h b/include/odp/api/abi-default/hash.h new file mode 100644 index 000000000..06e9e06c4 --- /dev/null +++ b/include/odp/api/abi-default/hash.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * ODP hash + */ + +#ifndef ODP_ABI_HASH_H_ +#define ODP_ABI_HASH_H_ + +/* Empty header to allow platforms to override inlining + * of hash functions. + */ + +#endif diff --git a/include/odp/api/errno.h b/include/odp/api/errno.h index a0da42ff4..212e51244 100644 --- a/include/odp/api/errno.h +++ b/include/odp/api/errno.h @@ -17,6 +17,8 @@ extern "C" { #endif +#include <odp/api/abi/errno.h> + #include <odp/api/spec/errno.h> #ifdef __cplusplus diff --git a/include/odp/api/hash.h b/include/odp/api/hash.h index b1ddf897a..f059d51ce 100644 --- a/include/odp/api/hash.h +++ b/include/odp/api/hash.h @@ -17,6 +17,8 @@ extern "C" { #endif +#include <odp/api/abi/hash.h> + #include <odp/api/spec/hash.h> #ifdef __cplusplus diff --git a/include/odp/api/spec/packet_io.h b/include/odp/api/spec/packet_io.h index d97e45960..b7eaccaa3 100644 --- a/include/odp/api/spec/packet_io.h +++ b/include/odp/api/spec/packet_io.h @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited + * Copyright (c) 2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -1208,16 +1209,22 @@ void odp_pktio_config_init(odp_pktio_config_t *config); */ void odp_pktio_print(odp_pktio_t pktio); +/** Link status */ +typedef enum odp_pktio_link_status_t { + ODP_PKTIO_LINK_STATUS_UNKNOWN = -1, + ODP_PKTIO_LINK_STATUS_DOWN = 0, + ODP_PKTIO_LINK_STATUS_UP = 1 +} odp_pktio_link_status_t; + /** * Determine pktio link is up or down for a packet IO interface. * * @param pktio Packet IO handle. * - * @retval 1 link is up - * @retval 0 link is down - * @retval <0 on failure + * @retval ODP_PKTIO_LINK_STATUS_UP or ODP_PKTIO_LINK_STATUS_DOWN on success + * @retval ODP_PKTIO_LINK_STATUS_UNKNOWN on failure */ -int odp_pktio_link_status(odp_pktio_t pktio); +odp_pktio_link_status_t odp_pktio_link_status(odp_pktio_t pktio); /** * Packet IO information @@ -1255,6 +1262,112 @@ typedef struct odp_pktio_info_t { */ int odp_pktio_info(odp_pktio_t pktio, odp_pktio_info_t *info); +/** @name Link speed + * Packet IO link speeds in Mbps + * @anchor link_speed + * @{ + */ + +/** Link speed unknown */ +#define ODP_PKTIO_LINK_SPEED_UNKNOWN 0 +/** Link speed 10 Mbit/s */ +#define ODP_PKTIO_LINK_SPEED_10M 10 +/** Link speed 100 Mbit/s */ +#define ODP_PKTIO_LINK_SPEED_100M 100 +/** Link speed 1 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_1G 1000 +/** Link speed 2.5 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_2_5G 2500 +/** Link speed 5 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_5G 5000 +/** Link speed 10 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_10G 10000 +/** Link speed 20 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_20G 20000 +/** Link speed 25 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_25G 25000 +/** Link speed 40 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_40G 40000 +/** Link speed 50 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_50G 50000 +/** Link speed 56 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_56G 56000 +/** Link speed 100 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_100G 100000 +/** Link speed 200 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_200G 200000 +/** Link speed 400 Gbit/s */ +#define ODP_PKTIO_LINK_SPEED_400G 400000 + +/** @} */ + +/** Autonegotiation mode */ +typedef enum odp_pktio_link_autoneg_t { + /** Autonegotiation state unknown */ + ODP_PKTIO_LINK_AUTONEG_UNKNOWN = -1, + /** Autonegotiation disabled */ + ODP_PKTIO_LINK_AUTONEG_OFF = 0, + /** Autonegotiation enabled */ + ODP_PKTIO_LINK_AUTONEG_ON = 1 +} odp_pktio_link_autoneg_t; + +/** Duplex mode */ +typedef enum odp_pktio_link_duplex_t { + ODP_PKTIO_LINK_DUPLEX_UNKNOWN = -1, + ODP_PKTIO_LINK_DUPLEX_HALF = 0, + ODP_PKTIO_LINK_DUPLEX_FULL = 1 +} odp_pktio_link_duplex_t; + +/** Ethernet pause frame (flow control) mode */ +typedef enum odp_pktio_link_pause_t { + ODP_PKTIO_LINK_PAUSE_UNKNOWN = -1, + ODP_PKTIO_LINK_PAUSE_OFF = 0, + ODP_PKTIO_LINK_PAUSE_ON = 1 +} odp_pktio_link_pause_t; + +/** + * Packet IO link information + */ +typedef struct odp_pktio_link_info_t { + /** Link autonegotiation */ + odp_pktio_link_autoneg_t autoneg; + /** Duplex mode */ + odp_pktio_link_duplex_t duplex; + /** Link media type + * + * The implementation owned string describes link media type. Values are + * implementation specific short names like copper, fiber, or virtual. + * The value of "unknown" is used when media type cannot be determined. */ + const char *media; + /** Reception of pause frames */ + odp_pktio_link_pause_t pause_rx; + /** Transmission of pause frames */ + odp_pktio_link_pause_t pause_tx; + /** Link speed in Mbps + * + * The value of zero means that the link speed is unknown. + * ODP_PKTIO_LINK_SPEED_* (@ref link_speed) defines can be used to + * compare the value to standard link speeds. */ + uint32_t speed; + /** Link status */ + odp_pktio_link_status_t status; +} odp_pktio_link_info_t; + +/** + * Retrieve information about packet IO link status + * + * Fills in link information structure with the current link status values. + * May be called any time with a valid pktio handle. The call is not intended + * for fast path use. The info structure is written only on success. + * + * @param pktio Packet IO handle + * @param[out] info Pointer to packet IO link info struct for output + * + * @retval 0 on success + * @retval <0 on failure + */ +int odp_pktio_link_info(odp_pktio_t pktio, odp_pktio_link_info_t *info); + /** * Packet input timestamp resolution in hertz * diff --git a/include/odp/api/spec/random.h b/include/odp/api/spec/random.h index 89d7d9d3f..80f71c473 100644 --- a/include/odp/api/spec/random.h +++ b/include/odp/api/spec/random.h @@ -72,7 +72,7 @@ odp_random_kind_t odp_random_max_kind(void); * is expected to fail if the implementation is unable to * provide the requested type. * - * @return Number of bytes written + * @return Number of bytes written (0...len). * @retval <0 on failure */ int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t kind); @@ -96,7 +96,7 @@ int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t kind); * variable. Results are undefined if multiple threads * call this routine with the same seed variable. * - * @return Number of bytes written + * @return Number of bytes written (always len) * @retval <0 on failure */ int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed); diff --git a/include/odp/api/spec/time.h b/include/odp/api/spec/time.h index c0a12064d..c5756e492 100644 --- a/include/odp/api/spec/time.h +++ b/include/odp/api/spec/time.h @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited + * Copyright (c) 2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -77,6 +78,24 @@ odp_time_t odp_time_local(void); odp_time_t odp_time_global(void); /** + * Current local time in nanoseconds + * + * Like odp_time_local(), but the time stamp value is converted into nanoseconds. + * + * @return Local time stamp in nanoseconds + */ +uint64_t odp_time_local_ns(void); + +/** + * Current global time in nanoseconds + * + * Like odp_time_global(), but the time stamp value is converted into nanoseconds. + * + * @return Global time stamp in nanoseconds + */ +uint64_t odp_time_global_ns(void); + +/** * Time difference * * @param t2 Second time stamp diff --git a/include/odp/api/spec/timer.h b/include/odp/api/spec/timer.h index a48e79bf5..1f49e7b40 100644 --- a/include/odp/api/spec/timer.h +++ b/include/odp/api/spec/timer.h @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * * All rights reserved. * @@ -106,14 +106,20 @@ typedef enum { typedef struct { /** Timeout resolution in nanoseconds. Timer pool must serve timeouts * with this or higher resolution. The minimum valid value (highest - * resolution) is defined by timer capability 'highest_res_ns'. */ + * resolution) is defined by timer resolution capability. When this + * parameter is used, set 'res_hz' to zero. */ uint64_t res_ns; + /** Timeout resolution in hertz. This may be used to specify the highest + * required resolution in hertz instead of nanoseconds. When this + * parameter is used, set 'res_ns' to zero. */ + uint64_t res_hz; + /** Minimum relative timeout in nanoseconds. All requested timeouts * will be at least this many nanoseconds after the current * time of the timer pool. Timer set functions return an error, if too - * short timeout was requested. The value may be also less than - * 'res_ns'. */ + * short timeout was requested. The value may be also smaller than + * the requested resolution. */ uint64_t min_tmo; /** Maximum relative timeout in nanoseconds. All requested timeouts @@ -143,6 +149,9 @@ typedef struct { /** Timeout resolution in nanoseconds */ uint64_t res_ns; + /** Timeout resolution in hertz */ + uint64_t res_hz; + /** Minimum relative timeout in nanoseconds */ uint64_t min_tmo; @@ -186,8 +195,9 @@ typedef struct { * * This defines the highest resolution supported by a timer, with * limits to min/max timeout values. The highest resolution for a timer - * pool is defined by 'max_res.res_ns', therefore it's the minimum value - * for 'res_ns' timer pool parameter. When this resolution is used: + * pool is defined by 'max_res.res_ns' in nanoseconds and + * 'max_res.res_hz' in hertz. + * When this resolution is used: * - 'min_tmo' parameter value must be in minimum 'max_res.min_tmo' * - 'max_tmo' parameter value must be in maximum 'max_res.max_tmo' */ @@ -201,7 +211,8 @@ typedef struct { * value for 'max_tmo' timer pool parameter is defined by * 'max_tmo.max_tmo'. When this max timeout value is used: * - 'min_tmo' parameter value must be in minimum 'max_tmo.min_tmo' - * - 'res_ns' parameter value must be in minimum 'max_tmo.res_ns' + * - 'res_ns' parameter value must be in minimum 'max_tmo.res_ns' or + * - 'res_hz' parameter value must be in maximum 'max_tmo.res_hz' */ odp_timer_res_capability_t max_tmo; @@ -226,16 +237,16 @@ int odp_timer_capability(odp_timer_clk_src_t clk_src, * * This function fills in capability limits for timer pool resolution and * min/max timeout values, based on either resolution or maximum timeout. - * Set the required value to 'res_ns' or 'max_tmo', and set other fields to - * zero. A successful call fills in the other two fields. The call returns - * a failure, if the user defined value ('res_ns' or 'max_tmo)' exceeds - * capability limits. Outputted values are minimums for 'res_ns' and 'min_tmo', - * and a maximum for 'max_tmo'. + * Set the required value to a resolution field (res_ns or res_hz) or to the + * maximum timeout field (max_tmo), and set other fields to zero. A successful + * call fills in the other fields. The call returns a failure, if the user + * defined value exceeds capability limits. Outputted values are minimums for + * 'res_ns' and 'min_tmo', and maximums for 'res_hz' and 'max_tmo'. * * @param clk_src Clock source for timers * @param[in,out] res_capa Resolution capability pointer for input/output. - * Set either 'res_ns' or 'max_tmo', a successful call - * fills in other fields. + * Set either a resolution or max timeout field, + * a successful call fills in other fields. * * @retval 0 on success * @retval <0 on failure diff --git a/include/odp/api/spec/traffic_mngr.h b/include/odp/api/spec/traffic_mngr.h index 03294c820..04848a0ea 100644 --- a/include/odp/api/spec/traffic_mngr.h +++ b/include/odp/api/spec/traffic_mngr.h @@ -1651,7 +1651,8 @@ typedef struct { /** Get tm_node Info * * The odp_tm_node_info() function is used to extract various bits of - * configuration associated with a given tm_node. + * configuration associated with a given tm_node. The info structure is written + * only on success. * * @param tm_node Specifies the tm_node to be queried. * @param[out] info A pointer to an odp_tm_node_info_t record that is to @@ -1711,7 +1712,7 @@ typedef struct { * from their fanin list, a reasonable list walk can occur - even while past or * future entries are being removed or while future entries are being added. * Note that all new additions to a fanin list always take place at the end of - * the list. + * the list. The info structure is written only on success. * * @param tm_node Specifies the tm_node to be queried. * @param[in,out] info A pointer to an odp_tm_node_fanin_info_t record that @@ -1756,7 +1757,8 @@ typedef struct { /** Get tm_queue Info * * The odp_tm_queue_info() function is used to extract various bits of - * configuration associated with a given tm_queue. + * configuration associated with a given tm_queue. The info structure is + * written only on success. * * @param tm_queue Specifies the tm_queue to be queried. * @param[out] info A pointer to an odp_tm_queue_info_t record that is to @@ -1840,11 +1842,12 @@ typedef struct { * byte counts or both are being requested. It is an error to request * neither. The implementation may still return both sets of counts * regardless of query_flags if the cost of returning all the counts is - * comparable to the cost of checking the query_flags. + * comparable to the cost of checking the query_flags. The info structure is + * written only on success. * * @param tm_queue Specifies the tm_queue (and indirectly the * TM system). - * @param[out] query_flags A set of flag bits indicating which counters are + * @param query_flags A set of flag bits indicating which counters are * being requested to be returned in the info record. * @param[out] info Pointer to an odp_tm_query_info_t record where the * requested queue info is returned. @@ -1860,12 +1863,12 @@ int odp_tm_queue_query(odp_tm_queue_t tm_queue, * requested. It is an error to request neither. The implementation may * still return both sets of counts regardless of query_flags if the cost of * returning all the counts is comparable to the cost of checking the - * query_flags. + * query_flags. The info structure is written only on success. * * @param odp_tm Specifies the TM system. * @param priority Supplies the strict priority level used to specify * which tm_queues are included in the info values. - * @param[out] query_flags A set of flag bits indicating which counters are + * @param query_flags A set of flag bits indicating which counters are * being requested to be returned in the info record. * @param[out] info Pointer to an odp_tm_query_info_t record where the * requested queue info is returned. @@ -1882,10 +1885,10 @@ int odp_tm_priority_query(odp_tm_t odp_tm, * requested. It is an error to request neither. The implementation may * still return both sets of counts regardless of query_flags if the cost of * returning all the counts is comparable to the cost of checking the - * query_flags. + * query_flags. The info structure is written only on success. * * @param odp_tm Specifies the TM system. - * @param[out] query_flags A set of flag bits indicating which counters are + * @param query_flags A set of flag bits indicating which counters are * being requested to be returned in the info record. * @param[out] info Pointer to an odp_tm_query_info_t record where the * requested queue info is returned. @@ -1952,6 +1955,97 @@ odp_bool_t odp_tm_is_idle(odp_tm_t odp_tm); void odp_tm_stats_print(odp_tm_t odp_tm); /** + * Get printable value for an odp_tm_t + * + * @param hdl odp_tm_t handle to be printed + * @return uint64_t value that can be used to print/display this + * handle + * + * @note This routine is intended to be used for diagnostic purposes + * to enable applications to generate a printable value that represents + * an odp_tm_t handle. + */ +uint64_t odp_tm_to_u64(odp_tm_t hdl); + +/** + * Get printable value for an odp_tm_queue_t + * + * @param hdl odp_tm_queue_t handle to be printed + * @return uint64_t value that can be used to print/display this + * handle + * + * @note This routine is intended to be used for diagnostic purposes + * to enable applications to generate a printable value that represents + * an odp_tm_queue_t handle. + */ +uint64_t odp_tm_queue_to_u64(odp_tm_queue_t hdl); + +/** + * Get printable value for an odp_tm_node_t + * + * @param hdl odp_tm_node_t handle to be printed + * @return uint64_t value that can be used to print/display this + * handle + * + * @note This routine is intended to be used for diagnostic purposes + * to enable applications to generate a printable value that represents + * an odp_tm_node_t handle. + */ +uint64_t odp_tm_node_to_u64(odp_tm_node_t hdl); + +/** + * Get printable value for an odp_tm_shaper_t + * + * @param hdl odp_tm_shaper_t handle to be printed + * @return uint64_t value that can be used to print/display this + * handle + * + * @note This routine is intended to be used for diagnostic purposes + * to enable applications to generate a printable value that represents + * an odp_tm_shaper_t handle. + */ +uint64_t odp_tm_shaper_to_u64(odp_tm_shaper_t hdl); + +/** + * Get printable value for an odp_tm_sched_t + * + * @param hdl odp_tm_sched_t handle to be printed + * @return uint64_t value that can be used to print/display this + * handle + * + * @note This routine is intended to be used for diagnostic purposes + * to enable applications to generate a printable value that represents + * an odp_tm_sched_t handle. + */ +uint64_t odp_tm_sched_to_u64(odp_tm_sched_t hdl); + +/** + * Get printable value for an odp_tm_threshold_t + * + * @param hdl odp_tm_threshold_t handle to be printed + * @return uint64_t value that can be used to print/display this + * handle + * + * @note This routine is intended to be used for diagnostic purposes + * to enable applications to generate a printable value that represents + * an odp_tm_threshold_t handle. + */ +uint64_t odp_tm_threshold_to_u64(odp_tm_threshold_t hdl); + +/** + * Get printable value for an odp_tm_wred_t + * + * @param hdl odp_tm_wred_t handle to be printed + * @return uint64_t value that can be used to print/display this + * handle + * + * @note This routine is intended to be used for diagnostic purposes + * to enable applications to generate a printable value that represents + * an odp_tm_wred_t handle. + */ +uint64_t odp_tm_wred_to_u64(odp_tm_wred_t hdl); + +/** * @} */ diff --git a/include/odp/arch/arm32-linux/odp/api/abi/errno.h b/include/odp/arch/arm32-linux/odp/api/abi/errno.h new file mode 100644 index 000000000..69de49a0b --- /dev/null +++ b/include/odp/arch/arm32-linux/odp/api/abi/errno.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/errno.h> diff --git a/include/odp/arch/arm32-linux/odp/api/abi/hash.h b/include/odp/arch/arm32-linux/odp/api/abi/hash.h new file mode 100644 index 000000000..c9fb1976c --- /dev/null +++ b/include/odp/arch/arm32-linux/odp/api/abi/hash.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/hash.h> diff --git a/include/odp/arch/arm64-linux/odp/api/abi/errno.h b/include/odp/arch/arm64-linux/odp/api/abi/errno.h new file mode 100644 index 000000000..69de49a0b --- /dev/null +++ b/include/odp/arch/arm64-linux/odp/api/abi/errno.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/errno.h> diff --git a/include/odp/arch/arm64-linux/odp/api/abi/hash.h b/include/odp/arch/arm64-linux/odp/api/abi/hash.h new file mode 100644 index 000000000..c9fb1976c --- /dev/null +++ b/include/odp/arch/arm64-linux/odp/api/abi/hash.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/hash.h> diff --git a/include/odp/arch/default-linux/odp/api/abi/errno.h b/include/odp/arch/default-linux/odp/api/abi/errno.h new file mode 100644 index 000000000..69de49a0b --- /dev/null +++ b/include/odp/arch/default-linux/odp/api/abi/errno.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/errno.h> diff --git a/include/odp/arch/default-linux/odp/api/abi/hash.h b/include/odp/arch/default-linux/odp/api/abi/hash.h new file mode 100644 index 000000000..c9fb1976c --- /dev/null +++ b/include/odp/arch/default-linux/odp/api/abi/hash.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/hash.h> diff --git a/include/odp/arch/mips64-linux/odp/api/abi/errno.h b/include/odp/arch/mips64-linux/odp/api/abi/errno.h new file mode 100644 index 000000000..69de49a0b --- /dev/null +++ b/include/odp/arch/mips64-linux/odp/api/abi/errno.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/errno.h> diff --git a/include/odp/arch/mips64-linux/odp/api/abi/hash.h b/include/odp/arch/mips64-linux/odp/api/abi/hash.h new file mode 100644 index 000000000..c9fb1976c --- /dev/null +++ b/include/odp/arch/mips64-linux/odp/api/abi/hash.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/hash.h> diff --git a/include/odp/arch/power64-linux/odp/api/abi/errno.h b/include/odp/arch/power64-linux/odp/api/abi/errno.h new file mode 100644 index 000000000..69de49a0b --- /dev/null +++ b/include/odp/arch/power64-linux/odp/api/abi/errno.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/errno.h> diff --git a/include/odp/arch/power64-linux/odp/api/abi/hash.h b/include/odp/arch/power64-linux/odp/api/abi/hash.h new file mode 100644 index 000000000..c9fb1976c --- /dev/null +++ b/include/odp/arch/power64-linux/odp/api/abi/hash.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/hash.h> diff --git a/include/odp/arch/x86_32-linux/odp/api/abi/errno.h b/include/odp/arch/x86_32-linux/odp/api/abi/errno.h new file mode 100644 index 000000000..69de49a0b --- /dev/null +++ b/include/odp/arch/x86_32-linux/odp/api/abi/errno.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/errno.h> diff --git a/include/odp/arch/x86_32-linux/odp/api/abi/hash.h b/include/odp/arch/x86_32-linux/odp/api/abi/hash.h new file mode 100644 index 000000000..c9fb1976c --- /dev/null +++ b/include/odp/arch/x86_32-linux/odp/api/abi/hash.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/hash.h> diff --git a/include/odp/arch/x86_64-linux/odp/api/abi/errno.h b/include/odp/arch/x86_64-linux/odp/api/abi/errno.h new file mode 100644 index 000000000..69de49a0b --- /dev/null +++ b/include/odp/arch/x86_64-linux/odp/api/abi/errno.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/errno.h> diff --git a/include/odp/arch/x86_64-linux/odp/api/abi/hash.h b/include/odp/arch/x86_64-linux/odp/api/abi/hash.h new file mode 100644 index 000000000..c9fb1976c --- /dev/null +++ b/include/odp/arch/x86_64-linux/odp/api/abi/hash.h @@ -0,0 +1,7 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/abi-default/hash.h> diff --git a/m4/odp_atomic.m4 b/m4/odp_atomic.m4 index c0068b5e4..cde313261 100644 --- a/m4/odp_atomic.m4 +++ b/m4/odp_atomic.m4 @@ -126,12 +126,13 @@ AC_CACHE_CHECK([whether -latomic is needed for 64-bit atomic compare exchange], [odp_cv_atomic_needed_64bit_cmp_exc], [dnl AC_LINK_IFELSE( [AC_LANG_SOURCE([[ + #include <stdbool.h> #include <stdint.h> static uint64_t loc; int main(void) { uint64_t exp = 0; - uint64_t = __atomic_compare_exchange_n(&loc, &exp, 1, 1, + bool res = __atomic_compare_exchange_8(&loc, &exp, 1, 1, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED); return 0; @@ -157,14 +158,14 @@ AC_CACHE_CHECK([whether -latomic is needed for 128-bit atomic compare exchange], [odp_cv_atomic_needed_128bit_cmp_exc], [dnl AC_LINK_IFELSE( [AC_LANG_SOURCE([[ - #include <stdint.h> + #include <stdbool.h> static __int128 loc; int main(void) { __int128 exp = 0; - __int128 = __atomic_compare_exchange_n(&loc, &exp, 1, 1, - __ATOMIC_ACQUIRE, - __ATOMIC_RELAXED); + bool res = __atomic_compare_exchange_16(&loc, &exp, 1, 1, + __ATOMIC_ACQUIRE, + __ATOMIC_RELAXED); return 0; } ]])], diff --git a/platform/Makefile.inc b/platform/Makefile.inc index f99d39ffc..475d38c37 100644 --- a/platform/Makefile.inc +++ b/platform/Makefile.inc @@ -1,18 +1,18 @@ include $(top_srcdir)/Makefile.inc pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libodp-linux.pc +pkgconfig_DATA = lib$(ODP_LIB_NAME).pc EXTRA_DIST = doc/platform_specific.dox configdir = $(sysconfdir)/odp if ODP_USE_CONFIG -config_DATA = $(top_srcdir)/config/odp-$(with_platform).conf -EXTRA_DIST += $(top_srcdir)/config/odp-$(with_platform).conf +config_DATA = $(top_builddir)/$(rel_default_config_path) +EXTRA_DIST += $(top_builddir)/$(rel_default_config_path) endif VPATH = $(srcdir) $(builddir) -lib_LTLIBRARIES = $(LIB)/libodp-linux.la +lib_LTLIBRARIES = AM_LDFLAGS = -version-number '$(ODP_LIBSO_VERSION)' diff --git a/platform/linux-dpdk/Makefile.am b/platform/linux-dpdk/Makefile.am index 30e9f1dbd..045051b79 100644 --- a/platform/linux-dpdk/Makefile.am +++ b/platform/linux-dpdk/Makefile.am @@ -1,5 +1,6 @@ include $(top_srcdir)/platform/Makefile.inc include $(top_srcdir)/platform/@with_platform@/Makefile.inc +lib_LTLIBRARIES += $(LIB)/libodp-linux.la AM_CPPFLAGS = $(ODP_INCLUDES) AM_CPPFLAGS += -I$(top_srcdir)/platform/$(with_platform)/include @@ -15,7 +16,7 @@ AM_CFLAGS += $(DPDK_CFLAGS) AM_CFLAGS += $(LIBCONFIG_CFLAGS) DISTCLEANFILES = include/odp_libconfig_config.h -include/odp_libconfig_config.h: $(top_srcdir)/config/odp-$(with_platform).conf $(top_builddir)/config.status +include/odp_libconfig_config.h: $(top_builddir)/$(rel_default_config_path) $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ odpapiabiarchincludedir = $(archincludedir)/odp/api/abi @@ -55,7 +56,9 @@ odpapiabiarchinclude_HEADERS += \ include-abi/odp/api/abi/cpumask.h \ include-abi/odp/api/abi/crypto.h \ include-abi/odp/api/abi/debug.h \ + include-abi/odp/api/abi/errno.h \ include-abi/odp/api/abi/event.h \ + include-abi/odp/api/abi/hash.h \ include-abi/odp/api/abi/init.h \ include-abi/odp/api/abi/ipsec.h \ include-abi/odp/api/abi/packet.h \ @@ -138,7 +141,7 @@ noinst_HEADERS = \ include/protocols/udp.h \ Makefile.inc -nodist_noinst_HEADERS = \ +BUILT_SOURCES = \ include/odp_libconfig_config.h __LIB__libodp_linux_la_SOURCES = \ diff --git a/platform/linux-dpdk/include-abi/odp/api/abi/errno.h b/platform/linux-dpdk/include-abi/odp/api/abi/errno.h new file mode 120000 index 000000000..0bc8b623d --- /dev/null +++ b/platform/linux-dpdk/include-abi/odp/api/abi/errno.h @@ -0,0 +1 @@ +../../../../../linux-generic/include-abi/odp/api/abi/errno.h
\ No newline at end of file diff --git a/platform/linux-dpdk/include-abi/odp/api/abi/hash.h b/platform/linux-dpdk/include-abi/odp/api/abi/hash.h new file mode 120000 index 000000000..cdcd8260a --- /dev/null +++ b/platform/linux-dpdk/include-abi/odp/api/abi/hash.h @@ -0,0 +1 @@ +../../../../../linux-generic/include-abi/odp/api/abi/hash.h
\ No newline at end of file diff --git a/platform/linux-dpdk/include/odp/api/plat/time_inlines.h b/platform/linux-dpdk/include/odp/api/plat/time_inlines.h index 0b49c09d6..a1b91682a 100644 --- a/platform/linux-dpdk/include/odp/api/plat/time_inlines.h +++ b/platform/linux-dpdk/include/odp/api/plat/time_inlines.h @@ -1,4 +1,5 @@ /* Copyright (c) 2018, Linaro Limited + * Copyright (c) 2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -17,6 +18,7 @@ /** @cond _ODP_HIDE_FROM_DOXYGEN_ */ #define _ODP_TIMESPEC_SIZE 16 +#define _ODP_TIME_GIGA_HZ 1000000000ULL typedef odp_time_t (*time_cur_fn)(void); typedef uint64_t (*time_res_fn)(void); @@ -61,14 +63,43 @@ static inline odp_time_t _odp_time_cur(void) return _odp_time_glob.handler.time_cur(); } +static inline uint64_t _odp_time_hw_to_ns(odp_time_t time) +{ + uint64_t nsec; + uint64_t freq_hz = _odp_time_glob.hw_freq_hz; + uint64_t count = time.count; + uint64_t sec = 0; + + if (count >= freq_hz) { + sec = count / freq_hz; + count = count - sec * freq_hz; + } + + nsec = (_ODP_TIME_GIGA_HZ * count) / freq_hz; + + return (sec * _ODP_TIME_GIGA_HZ) + nsec; +} + +static inline uint64_t _odp_time_convert_to_ns(odp_time_t time) +{ + if (_odp_time_glob.use_hw) + return _odp_time_hw_to_ns(time); + + return time.nsec; +} + #ifndef _ODP_NO_INLINE /* Inline functions by default */ #define _ODP_INLINE static inline - #define odp_time_local __odp_time_local - #define odp_time_global __odp_time_global - #define odp_time_cmp __odp_time_cmp - #define odp_time_diff __odp_time_diff - #define odp_time_sum __odp_time_sum + #define odp_time_local __odp_time_local + #define odp_time_global __odp_time_global + #define odp_time_to_ns __odp_time_to_ns + #define odp_time_local_ns __odp_time_local_ns + #define odp_time_global_ns __odp_time_global_ns + #define odp_time_cmp __odp_time_cmp + #define odp_time_diff __odp_time_diff + #define odp_time_sum __odp_time_sum + #else #define _ODP_INLINE #endif @@ -83,6 +114,21 @@ _ODP_INLINE odp_time_t odp_time_global(void) return _odp_time_cur(); } +_ODP_INLINE uint64_t odp_time_to_ns(odp_time_t time) +{ + return _odp_time_convert_to_ns(time); +} + +_ODP_INLINE uint64_t odp_time_local_ns(void) +{ + return _odp_time_convert_to_ns(_odp_time_cur()); +} + +_ODP_INLINE uint64_t odp_time_global_ns(void) +{ + return _odp_time_convert_to_ns(_odp_time_cur()); +} + _ODP_INLINE int odp_time_cmp(odp_time_t t2, odp_time_t t1) { if (odp_likely(t2.u64 > t1.u64)) diff --git a/platform/linux-dpdk/include/odp_packet_io_internal.h b/platform/linux-dpdk/include/odp_packet_io_internal.h index 5bc3a3590..44c8774f6 100644 --- a/platform/linux-dpdk/include/odp_packet_io_internal.h +++ b/platform/linux-dpdk/include/odp_packet_io_internal.h @@ -159,6 +159,7 @@ typedef struct pktio_if_ops { int (*mac_get)(pktio_entry_t *pktio_entry, void *mac_addr); int (*mac_set)(pktio_entry_t *pktio_entry, const void *mac_addr); int (*link_status)(pktio_entry_t *pktio_entry); + int (*link_info)(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info); int (*capability)(pktio_entry_t *pktio_entry, odp_pktio_capability_t *capa); int (*config)(pktio_entry_t *pktio_entry, diff --git a/platform/linux-dpdk/libodp-linux.pc.in b/platform/linux-dpdk/libodp-linux.pc.in index 5b9421226..39729ea58 100644 --- a/platform/linux-dpdk/libodp-linux.pc.in +++ b/platform/linux-dpdk/libodp-linux.pc.in @@ -3,10 +3,10 @@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ -Name: libodp-linux +Name: lib@ODP_LIB_NAME@ Description: The ODP packet processing engine Version: @PKGCONFIG_VERSION@ Requires.private: libconfig@DPDK_PKG@ -Libs: -L${libdir} -lodp-linux @DPDK_LIBS_NON_ABI_COMPAT@ +Libs: -L${libdir} -l@ODP_LIB_NAME@ @DPDK_LIBS_NON_ABI_COMPAT@ Libs.private: @DPDK_LIBS_ABI_COMPAT@ @OPENSSL_STATIC_LIBS@ @PTHREAD_LIBS@ @TIMER_LIBS@ -lpthread @ATOMIC_LIBS@ Cflags: -I${includedir} @DPDK_CFLAGS@ diff --git a/platform/linux-dpdk/m4/configure.m4 b/platform/linux-dpdk/m4/configure.m4 index 5172d9edd..9c5f02a35 100644 --- a/platform/linux-dpdk/m4/configure.m4 +++ b/platform/linux-dpdk/m4/configure.m4 @@ -1,4 +1,5 @@ ODP_IMPLEMENTATION_NAME="odp-dpdk" +ODP_LIB_NAME="odp-linux" ODP_VISIBILITY ODP_ATOMIC diff --git a/platform/linux-dpdk/m4/odp_libconfig.m4 b/platform/linux-dpdk/m4/odp_libconfig.m4 index 2ab6aa047..40d882d30 100644 --- a/platform/linux-dpdk/m4/odp_libconfig.m4 +++ b/platform/linux-dpdk/m4/odp_libconfig.m4 @@ -20,9 +20,16 @@ AC_SUBST(_ODP_CONFIG_VERSION_MINOR) ########################################################################## default_config_path="${srcdir}/config/odp-linux-dpdk.conf" +AC_CHECK_PROGS([REALPATH], [realpath]) +AS_IF([test -z "$REALPATH"], [AC_MSG_ERROR([Could not find 'realpath'])]) + AC_ARG_WITH([config-file], AS_HELP_STRING([--with-config-file=FILE path to the default configuration file], [(this file must include all configuration options).]), [default_config_path=$withval], []) -ODP_LIBCONFIG([linux-dpdk], [$default_config_path]) +rel_default_config_path=`realpath --relative-to=$(pwd) ${default_config_path}` +AC_SUBST(default_config_path) +AC_SUBST(rel_default_config_path) + +ODP_LIBCONFIG([linux-dpdk], [$rel_default_config_path]) diff --git a/platform/linux-dpdk/odp_packet_dpdk.c b/platform/linux-dpdk/odp_packet_dpdk.c index ba3f47b8f..af7fce4af 100644 --- a/platform/linux-dpdk/odp_packet_dpdk.c +++ b/platform/linux-dpdk/odp_packet_dpdk.c @@ -1453,7 +1453,64 @@ static int link_status_pkt_dpdk(pktio_entry_t *pktio_entry) struct rte_eth_link link; rte_eth_link_get(pkt_priv(pktio_entry)->port_id, &link); - return link.link_status; + + if (link.link_status) + return ODP_PKTIO_LINK_STATUS_UP; + return ODP_PKTIO_LINK_STATUS_DOWN; +} + +static int dpdk_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + struct rte_eth_link link; + struct rte_eth_fc_conf fc_conf; + uint16_t port_id = pkt_priv(pktio_entry)->port_id; + int ret; + + memset(&fc_conf, 0, sizeof(struct rte_eth_fc_conf)); + memset(&link, 0, sizeof(struct rte_eth_link)); + + ret = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf); + if (ret && ret != -ENOTSUP) { + ODP_ERR("rte_eth_dev_flow_ctrl_get() failed\n"); + return -1; + } + + memset(info, 0, sizeof(odp_pktio_link_info_t)); + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + if (fc_conf.mode == RTE_FC_RX_PAUSE) { + info->pause_rx = ODP_PKTIO_LINK_PAUSE_ON; + } else if (fc_conf.mode == RTE_FC_TX_PAUSE) { + info->pause_tx = ODP_PKTIO_LINK_PAUSE_ON; + } else if (fc_conf.mode == RTE_FC_FULL) { + info->pause_rx = ODP_PKTIO_LINK_PAUSE_ON; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_ON; + } + + rte_eth_link_get_nowait(port_id, &link); + if (link.link_autoneg == ETH_LINK_AUTONEG) + info->autoneg = ODP_PKTIO_LINK_AUTONEG_ON; + else + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + + if (link.link_duplex == ETH_LINK_FULL_DUPLEX) + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + else + info->duplex = ODP_PKTIO_LINK_DUPLEX_HALF; + + if (link.link_speed == ETH_SPEED_NUM_NONE) + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + else + info->speed = link.link_speed; + + if (link.link_status == ETH_LINK_UP) + info->status = ODP_PKTIO_LINK_STATUS_UP; + else + info->status = ODP_PKTIO_LINK_STATUS_DOWN; + + info->media = "unknown"; + + return 0; } static void stats_convert(struct rte_eth_stats *rte_stats, @@ -1514,6 +1571,7 @@ const pktio_if_ops_t dpdk_pktio_ops = { .mac_get = mac_get_pkt_dpdk, .mac_set = mac_set_pkt_dpdk, .link_status = link_status_pkt_dpdk, + .link_info = dpdk_link_info, .capability = capability_pkt_dpdk, .config = NULL, .input_queues_config = dpdk_input_queues_config, diff --git a/platform/linux-dpdk/odp_time.c b/platform/linux-dpdk/odp_time.c index 4cabc9b3b..f1489cf3c 100644 --- a/platform/linux-dpdk/odp_time.c +++ b/platform/linux-dpdk/odp_time.c @@ -81,11 +81,6 @@ static inline uint64_t time_spec_res(void) return ODP_TIME_SEC_IN_NS / (uint64_t)tres.tv_nsec; } -static inline uint64_t time_spec_to_ns(odp_time_t time) -{ - return time.nsec; -} - static inline odp_time_t time_spec_from_ns(uint64_t ns) { odp_time_t time; @@ -104,23 +99,6 @@ static inline uint64_t time_hw_res(void) return _odp_time_glob.hw_freq_hz; } -static inline uint64_t time_hw_to_ns(odp_time_t time) -{ - uint64_t nsec; - uint64_t freq_hz = _odp_time_glob.hw_freq_hz; - uint64_t count = time.count; - uint64_t sec = 0; - - if (count >= freq_hz) { - sec = count / freq_hz; - count = count - sec * freq_hz; - } - - nsec = (ODP_TIME_SEC_IN_NS * count) / freq_hz; - - return (sec * ODP_TIME_SEC_IN_NS) + nsec; -} - static inline odp_time_t time_hw_from_ns(uint64_t ns) { odp_time_t time; @@ -153,14 +131,6 @@ static inline uint64_t time_res(void) return time_spec_res(); } -static inline uint64_t time_to_ns(odp_time_t time) -{ - if (_odp_time_glob.use_hw) - return time_hw_to_ns(time); - - return time_spec_to_ns(time); -} - static inline odp_time_t time_from_ns(uint64_t ns) { if (_odp_time_glob.use_hw) @@ -198,12 +168,7 @@ uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1) time.u64 = t2.u64 - t1.u64; - return time_to_ns(time); -} - -uint64_t odp_time_to_ns(odp_time_t time) -{ - return time_to_ns(time); + return odp_time_to_ns(time); } odp_time_t odp_time_local_from_ns(uint64_t ns) diff --git a/platform/linux-dpdk/odp_timer.c b/platform/linux-dpdk/odp_timer.c index 460830239..3205c7d98 100644 --- a/platform/linux-dpdk/odp_timer.c +++ b/platform/linux-dpdk/odp_timer.c @@ -1,5 +1,5 @@ /* Copyright (c) 2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -25,6 +25,9 @@ #include <inttypes.h> #include <string.h> +/* One divided by one nanosecond in Hz */ +#define GIGA_HZ 1000000000 + /* Timer states */ #define NOT_TICKING 0 #define EXPIRED 1 @@ -52,6 +55,7 @@ ODP_STATIC_ASSERT(MAX_TIMERS < MAX_TIMER_RING_SIZE, /* Actual resolution depends on application polling frequency. Promise * 10 usec resolution. */ #define MAX_RES_NS 10000 +#define MAX_RES_HZ (GIGA_HZ / MAX_RES_NS) /* Limit minimum supported timeout in timer (CPU) cycles. Timer setup, polling, * timer management, timeout enqueue, etc takes about this many CPU cycles. @@ -267,9 +271,11 @@ int odp_timer_capability(odp_timer_clk_src_t clk_src, capa->max_timers = MAX_TIMERS; capa->highest_res_ns = MAX_RES_NS; capa->max_res.res_ns = MAX_RES_NS; + capa->max_res.res_hz = MAX_RES_HZ; capa->max_res.min_tmo = min_tmo; capa->max_res.max_tmo = MAX_TMO_NS; capa->max_tmo.res_ns = MAX_RES_NS; + capa->max_tmo.res_hz = MAX_RES_HZ; capa->max_tmo.min_tmo = min_tmo; capa->max_tmo.max_tmo = MAX_TMO_NS; @@ -291,12 +297,13 @@ int odp_timer_res_capability(odp_timer_clk_src_t clk_src, return -1; } - if (res_capa->res_ns) { + if (res_capa->res_ns || res_capa->res_hz) { res_capa->min_tmo = min_tmo; res_capa->max_tmo = MAX_TMO_NS; } else { /* max_tmo */ res_capa->min_tmo = min_tmo; res_capa->res_ns = MAX_RES_NS; + res_capa->res_hz = MAX_RES_HZ; } return 0; @@ -315,7 +322,18 @@ odp_timer_pool_t odp_timer_pool_create(const char *name, return ODP_TIMER_POOL_INVALID; } - if (param->res_ns < MAX_RES_NS) { + if ((param->res_ns && param->res_hz) || + (param->res_ns == 0 && param->res_hz == 0)) { + ODP_ERR("Invalid timeout resolution\n"); + return ODP_TIMER_POOL_INVALID; + } + + if (param->res_hz == 0 && param->res_ns < MAX_RES_NS) { + ODP_ERR("Too high resolution\n"); + return ODP_TIMER_POOL_INVALID; + } + + if (param->res_ns == 0 && param->res_hz > MAX_RES_HZ) { ODP_ERR("Too high resolution\n"); return ODP_TIMER_POOL_INVALID; } @@ -326,7 +344,12 @@ odp_timer_pool_t odp_timer_pool_create(const char *name, } num_timers = param->num_timers; - res_ns = param->res_ns; + + if (param->res_ns) + res_ns = param->res_ns; + else + res_ns = GIGA_HZ / param->res_hz; + /* Scan timer pool twice during resolution interval */ if (res_ns > ODP_TIME_USEC_IN_NS) @@ -376,6 +399,7 @@ odp_timer_pool_t odp_timer_pool_create(const char *name, } timer_pool->param = *param; + timer_pool->param.res_ns = res_ns; ring_u32_init(&timer_pool->free_timer.ring_hdr); timer_pool->free_timer.ring_mask = num_timers - 1; diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 2986e08e8..267d02a7d 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -2,6 +2,7 @@ #export CUSTOM_STR=https://github.com/OpenDataPlane/odp.git include $(top_srcdir)/platform/Makefile.inc +lib_LTLIBRARIES += $(LIB)/libodp-linux.la AM_CPPFLAGS = $(ODP_INCLUDES) AM_CPPFLAGS += -I$(top_srcdir)/platform/$(with_platform)/include @@ -17,7 +18,7 @@ AM_CFLAGS += $(DPDK_CFLAGS) AM_CFLAGS += $(LIBCONFIG_CFLAGS) DISTCLEANFILES = include/odp_libconfig_config.h -include/odp_libconfig_config.h: $(top_srcdir)/config/odp-$(with_platform).conf $(top_builddir)/config.status +include/odp_libconfig_config.h: $(top_builddir)/$(rel_default_config_path) $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ odpapiabiarchincludedir = $(archincludedir)/odp/api/abi @@ -57,7 +58,9 @@ odpapiabiarchinclude_HEADERS += \ include-abi/odp/api/abi/cpumask.h \ include-abi/odp/api/abi/crypto.h \ include-abi/odp/api/abi/debug.h \ + include-abi/odp/api/abi/errno.h \ include-abi/odp/api/abi/event.h \ + include-abi/odp/api/abi/hash.h \ include-abi/odp/api/abi/init.h \ include-abi/odp/api/abi/ipsec.h \ include-abi/odp/api/abi/packet.h \ @@ -148,7 +151,7 @@ noinst_HEADERS = \ include/protocols/tcp.h \ include/protocols/thash.h \ include/protocols/udp.h -nodist_noinst_HEADERS = \ +BUILT_SOURCES = \ include/odp_libconfig_config.h __LIB__libodp_linux_la_SOURCES = \ diff --git a/platform/linux-generic/include-abi/odp/api/abi/errno.h b/platform/linux-generic/include-abi/odp/api/abi/errno.h new file mode 100644 index 000000000..6215a0676 --- /dev/null +++ b/platform/linux-generic/include-abi/odp/api/abi/errno.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * ODP errno + */ + +#ifndef ODP_API_ABI_ERRNO_H_ +#define ODP_API_ABI_ERRNO_H_ + +#include <odp/api/abi-default/errno.h> + +#endif diff --git a/platform/linux-generic/include-abi/odp/api/abi/hash.h b/platform/linux-generic/include-abi/odp/api/abi/hash.h new file mode 100644 index 000000000..fc81dcc91 --- /dev/null +++ b/platform/linux-generic/include-abi/odp/api/abi/hash.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * ODP hash + */ + +#ifndef ODP_API_ABI_HASH_H_ +#define ODP_API_ABI_HASH_H_ + +#include <odp/api/abi-default/hash.h> + +#endif diff --git a/platform/linux-generic/include/odp/api/plat/time_inlines.h b/platform/linux-generic/include/odp/api/plat/time_inlines.h index 527490e3d..0b05aa4f7 100644 --- a/platform/linux-generic/include/odp/api/plat/time_inlines.h +++ b/platform/linux-generic/include/odp/api/plat/time_inlines.h @@ -1,4 +1,5 @@ /* Copyright (c) 2018, Linaro Limited + * Copyright (c) 2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -16,6 +17,7 @@ /** @cond _ODP_HIDE_FROM_DOXYGEN_ */ #define _ODP_TIMESPEC_SIZE 16 +#define _ODP_TIME_GIGA_HZ 1000000000ULL typedef struct _odp_time_global_t { /* Storage space for struct timespec. Posix headers are not included @@ -44,14 +46,42 @@ static inline odp_time_t _odp_time_cur(void) return _odp_timespec_cur(); } +static inline uint64_t _odp_time_hw_to_ns(odp_time_t time) +{ + uint64_t nsec; + uint64_t freq_hz = _odp_time_glob.hw_freq_hz; + uint64_t count = time.count; + uint64_t sec = 0; + + if (count >= freq_hz) { + sec = count / freq_hz; + count = count - sec * freq_hz; + } + + nsec = (_ODP_TIME_GIGA_HZ * count) / freq_hz; + + return (sec * _ODP_TIME_GIGA_HZ) + nsec; +} + +static inline uint64_t _odp_time_convert_to_ns(odp_time_t time) +{ + if (_odp_time_glob.use_hw) + return _odp_time_hw_to_ns(time); + + return time.nsec; +} + #ifndef _ODP_NO_INLINE /* Inline functions by default */ #define _ODP_INLINE static inline - #define odp_time_local __odp_time_local - #define odp_time_global __odp_time_global - #define odp_time_cmp __odp_time_cmp - #define odp_time_diff __odp_time_diff - #define odp_time_sum __odp_time_sum + #define odp_time_local __odp_time_local + #define odp_time_global __odp_time_global + #define odp_time_to_ns __odp_time_to_ns + #define odp_time_local_ns __odp_time_local_ns + #define odp_time_global_ns __odp_time_global_ns + #define odp_time_cmp __odp_time_cmp + #define odp_time_diff __odp_time_diff + #define odp_time_sum __odp_time_sum #else #define _ODP_INLINE @@ -67,6 +97,21 @@ _ODP_INLINE odp_time_t odp_time_global(void) return _odp_time_cur(); } +_ODP_INLINE uint64_t odp_time_to_ns(odp_time_t time) +{ + return _odp_time_convert_to_ns(time); +} + +_ODP_INLINE uint64_t odp_time_local_ns(void) +{ + return _odp_time_convert_to_ns(_odp_time_cur()); +} + +_ODP_INLINE uint64_t odp_time_global_ns(void) +{ + return _odp_time_convert_to_ns(_odp_time_cur()); +} + _ODP_INLINE int odp_time_cmp(odp_time_t t2, odp_time_t t1) { if (odp_likely(t2.u64 > t1.u64)) diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index 0e6a8a335..4219ff114 100644 --- a/platform/linux-generic/include/odp_packet_io_internal.h +++ b/platform/linux-generic/include/odp_packet_io_internal.h @@ -180,6 +180,7 @@ typedef struct pktio_if_ops { int (*mac_get)(pktio_entry_t *pktio_entry, void *mac_addr); int (*mac_set)(pktio_entry_t *pktio_entry, const void *mac_addr); int (*link_status)(pktio_entry_t *pktio_entry); + int (*link_info)(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info); int (*capability)(pktio_entry_t *pktio_entry, odp_pktio_capability_t *capa); int (*config)(pktio_entry_t *pktio_entry, diff --git a/platform/linux-generic/include/odp_socket_common.h b/platform/linux-generic/include/odp_socket_common.h index afce0f55d..0a9704076 100644 --- a/platform/linux-generic/include/odp_socket_common.h +++ b/platform/linux-generic/include/odp_socket_common.h @@ -12,6 +12,8 @@ extern "C" { #endif +#include <odp/api/packet_io.h> + #include <string.h> #include <linux/if_ether.h> @@ -57,6 +59,11 @@ int promisc_mode_get_fd(int fd, const char *name); */ int link_status_fd(int fd, const char *name); +/** + * Read link information from a packet socket + */ +int link_info_fd(int fd, const char *name, odp_pktio_link_info_t *info); + #ifdef __cplusplus } #endif diff --git a/platform/linux-generic/libodp-linux.pc.in b/platform/linux-generic/libodp-linux.pc.in index 5fe806435..df92e9345 100644 --- a/platform/linux-generic/libodp-linux.pc.in +++ b/platform/linux-generic/libodp-linux.pc.in @@ -3,10 +3,10 @@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ -Name: libodp-linux +Name: lib@ODP_LIB_NAME@ Description: The ODP packet processing engine Version: @PKGCONFIG_VERSION@ Requires.private: libconfig@DPDK_PKG@ -Libs: -L${libdir} -lodp-linux +Libs: -L${libdir} -l@ODP_LIB_NAME@ Libs.private: @OPENSSL_STATIC_LIBS@ @DPDK_LIBS@ @PCAP_LIBS@ @PTHREAD_LIBS@ @TIMER_LIBS@ -lpthread @ATOMIC_LIBS@ Cflags: -I${includedir} diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4 index bcd55b7c5..06bff0669 100644 --- a/platform/linux-generic/m4/configure.m4 +++ b/platform/linux-generic/m4/configure.m4 @@ -1,4 +1,5 @@ ODP_IMPLEMENTATION_NAME="odp-linux" +ODP_LIB_NAME="odp-linux" ODP_VISIBILITY ODP_ATOMIC diff --git a/platform/linux-generic/m4/odp_libconfig.m4 b/platform/linux-generic/m4/odp_libconfig.m4 index f042d65d7..d13fcf274 100644 --- a/platform/linux-generic/m4/odp_libconfig.m4 +++ b/platform/linux-generic/m4/odp_libconfig.m4 @@ -20,9 +20,16 @@ AC_SUBST(_ODP_CONFIG_VERSION_MINOR) ########################################################################## default_config_path="${srcdir}/config/odp-$with_platform.conf" +AC_CHECK_PROGS([REALPATH], [realpath]) +AS_IF([test -z "$REALPATH"], [AC_MSG_ERROR([Could not find 'realpath'])]) + AC_ARG_WITH([config-file], AS_HELP_STRING([--with-config-file=FILE path to the default configuration file], [(this file must include all configuration options).]), [default_config_path=$withval], []) -ODP_LIBCONFIG([$with_platform], [$default_config_path]) +rel_default_config_path=`realpath --relative-to=$(pwd) ${default_config_path}` +AC_SUBST(default_config_path) +AC_SUBST(rel_default_config_path) + +ODP_LIBCONFIG([$with_platform], [$rel_default_config_path]) diff --git a/platform/linux-generic/odp_crypto_openssl.c b/platform/linux-generic/odp_crypto_openssl.c index 98a13ce4a..2a8d4fb9b 100644 --- a/platform/linux-generic/odp_crypto_openssl.c +++ b/platform/linux-generic/odp_crypto_openssl.c @@ -285,6 +285,9 @@ odp_crypto_generic_session_t *alloc_session(void) } odp_spinlock_unlock(&global->lock); + if (!session) + return NULL; + session->idx = session - global->sessions; for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c index 1cd5745aa..d57c21a9e 100644 --- a/platform/linux-generic/odp_packet_io.c +++ b/platform/linux-generic/odp_packet_io.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -1168,15 +1168,15 @@ int odp_pktio_mac_addr_set(odp_pktio_t hdl, const void *mac_addr, int addr_size) return ret; } -int odp_pktio_link_status(odp_pktio_t hdl) +odp_pktio_link_status_t odp_pktio_link_status(odp_pktio_t hdl) { pktio_entry_t *entry; - int ret = -1; + int ret = ODP_PKTIO_LINK_STATUS_UNKNOWN; entry = get_pktio_entry(hdl); if (entry == NULL) { ODP_DBG("pktio entry %d does not exist\n", hdl); - return -1; + return ODP_PKTIO_LINK_STATUS_UNKNOWN; } lock_entry(entry); @@ -1184,7 +1184,7 @@ int odp_pktio_link_status(odp_pktio_t hdl) if (odp_unlikely(is_free(entry))) { unlock_entry(entry); ODP_DBG("already freed pktio\n"); - return -1; + return ODP_PKTIO_LINK_STATUS_UNKNOWN; } if (entry->s.ops->link_status) @@ -1244,6 +1244,23 @@ int odp_pktio_info(odp_pktio_t hdl, odp_pktio_info_t *info) return 0; } +int odp_pktio_link_info(odp_pktio_t hdl, odp_pktio_link_info_t *info) +{ + pktio_entry_t *entry; + + entry = get_pktio_entry(hdl); + + if (entry == NULL) { + ODP_DBG("pktio entry %d does not exist\n", hdl); + return -1; + } + + if (entry->s.ops->link_info) + return entry->s.ops->link_info(entry, info); + + return -1; +} + uint64_t odp_pktin_ts_res(odp_pktio_t hdl) { pktio_entry_t *entry; diff --git a/platform/linux-generic/odp_pool.c b/platform/linux-generic/odp_pool.c index d31f210e7..913e71f5a 100644 --- a/platform/linux-generic/odp_pool.c +++ b/platform/linux-generic/odp_pool.c @@ -666,9 +666,9 @@ static odp_pool_t pool_create(const char *name, const odp_pool_param_t *params, /* Allocate extra memory for skipping packet buffers which cross huge * page boundaries. */ if (params->type == ODP_POOL_PACKET) { - num_extra = (((uint64_t)(num * block_size) + + num_extra = ((((uint64_t)num * block_size) + FIRST_HP_SIZE - 1) / FIRST_HP_SIZE); - num_extra += (((uint64_t)(num_extra * block_size) + + num_extra += ((((uint64_t)num_extra * block_size) + FIRST_HP_SIZE - 1) / FIRST_HP_SIZE); } diff --git a/platform/linux-generic/odp_time.c b/platform/linux-generic/odp_time.c index b033a733c..aea823eb6 100644 --- a/platform/linux-generic/odp_time.c +++ b/platform/linux-generic/odp_time.c @@ -78,11 +78,6 @@ static inline uint64_t time_spec_res(void) return ODP_TIME_SEC_IN_NS / (uint64_t)tres.tv_nsec; } -static inline uint64_t time_spec_to_ns(odp_time_t time) -{ - return time.nsec; -} - static inline odp_time_t time_spec_from_ns(uint64_t ns) { odp_time_t time; @@ -101,23 +96,6 @@ static inline uint64_t time_hw_res(void) return _odp_time_glob.hw_freq_hz; } -static inline uint64_t time_hw_to_ns(odp_time_t time) -{ - uint64_t nsec; - uint64_t freq_hz = _odp_time_glob.hw_freq_hz; - uint64_t count = time.count; - uint64_t sec = 0; - - if (count >= freq_hz) { - sec = count / freq_hz; - count = count - sec * freq_hz; - } - - nsec = (ODP_TIME_SEC_IN_NS * count) / freq_hz; - - return (sec * ODP_TIME_SEC_IN_NS) + nsec; -} - static inline odp_time_t time_hw_from_ns(uint64_t ns) { odp_time_t time; @@ -150,14 +128,6 @@ static inline uint64_t time_res(void) return time_spec_res(); } -static inline uint64_t time_to_ns(odp_time_t time) -{ - if (_odp_time_glob.use_hw) - return time_hw_to_ns(time); - - return time_spec_to_ns(time); -} - static inline odp_time_t time_from_ns(uint64_t ns) { if (_odp_time_glob.use_hw) @@ -181,12 +151,7 @@ uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1) time.u64 = t2.u64 - t1.u64; - return time_to_ns(time); -} - -uint64_t odp_time_to_ns(odp_time_t time) -{ - return time_to_ns(time); + return odp_time_to_ns(time); } odp_time_t odp_time_local_from_ns(uint64_t ns) diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index 5fa020118..e7c0d4e51 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -54,6 +54,9 @@ /* Inlined API functions */ #include <odp/api/plat/event_inlines.h> +/* One divided by one nanosecond in Hz */ +#define GIGA_HZ 1000000000 + #define TMO_UNUSED ((uint64_t)0xFFFFFFFFFFFFFFFF) /* TMO_INACTIVE is or-ed with the expiration tick to indicate an expired timer. * The original expiration tick (63 bits) is still available so it can be used @@ -148,6 +151,7 @@ typedef struct timer_global_t { odp_shm_t shm; /* Max timer resolution in nanoseconds */ uint64_t highest_res_ns; + uint64_t highest_res_hz; uint64_t poll_interval_nsec; int num_timer_pools; uint8_t timer_pool_used[MAX_TIMER_POOLS]; @@ -324,7 +328,10 @@ static odp_timer_pool_t timer_pool_new(const char *name, memset(tp, 0, tp_size); - res_ns = param->res_ns; + if (param->res_ns) + res_ns = param->res_ns; + else + res_ns = GIGA_HZ / param->res_hz; /* Scan timer pool twice during resolution interval */ if (res_ns > ODP_TIME_USEC_IN_NS) @@ -344,6 +351,7 @@ static odp_timer_pool_t timer_pool_new(const char *name, } tp->shm = shm; tp->param = *param; + tp->param.res_ns = res_ns; tp->min_rel_tck = odp_timer_ns_to_tick(timer_pool_to_hdl(tp), param->min_tmo); tp->max_rel_tck = odp_timer_ns_to_tick(timer_pool_to_hdl(tp), @@ -1239,9 +1247,11 @@ int odp_timer_capability(odp_timer_clk_src_t clk_src, capa->max_timers = 0; capa->highest_res_ns = timer_global->highest_res_ns; capa->max_res.res_ns = timer_global->highest_res_ns; + capa->max_res.res_hz = timer_global->highest_res_hz; capa->max_res.min_tmo = 0; capa->max_res.max_tmo = MAX_TMO_NSEC; capa->max_tmo.res_ns = timer_global->highest_res_ns; + capa->max_tmo.res_hz = timer_global->highest_res_hz; capa->max_tmo.min_tmo = 0; capa->max_tmo.max_tmo = MAX_TMO_NSEC; @@ -1261,12 +1271,13 @@ int odp_timer_res_capability(odp_timer_clk_src_t clk_src, return -1; } - if (res_capa->res_ns) { + if (res_capa->res_ns || res_capa->res_hz) { res_capa->min_tmo = 0; res_capa->max_tmo = MAX_TMO_NSEC; } else { /* max_tmo */ res_capa->min_tmo = 0; res_capa->res_ns = timer_global->highest_res_ns; + res_capa->res_hz = timer_global->highest_res_hz; } return 0; @@ -1280,7 +1291,20 @@ odp_timer_pool_t odp_timer_pool_create(const char *name, return ODP_TIMER_POOL_INVALID; } - if (param->res_ns < timer_global->highest_res_ns) { + if ((param->res_ns && param->res_hz) || + (param->res_ns == 0 && param->res_hz == 0)) { + __odp_errno = EINVAL; + return ODP_TIMER_POOL_INVALID; + } + + if (param->res_hz == 0 && + param->res_ns < timer_global->highest_res_ns) { + __odp_errno = EINVAL; + return ODP_TIMER_POOL_INVALID; + } + + if (param->res_ns == 0 && + param->res_hz > timer_global->highest_res_hz) { __odp_errno = EINVAL; return ODP_TIMER_POOL_INVALID; } @@ -1561,6 +1585,9 @@ int _odp_timer_init_global(const odp_init_t *params) block_sigalarm(); } + /* timer_res_init() may update highest_res_ns */ + timer_global->highest_res_hz = GIGA_HZ / timer_global->highest_res_ns; + return 0; error: diff --git a/platform/linux-generic/odp_traffic_mngr.c b/platform/linux-generic/odp_traffic_mngr.c index de9cbfb73..1b6ca2ec2 100644 --- a/platform/linux-generic/odp_traffic_mngr.c +++ b/platform/linux-generic/odp_traffic_mngr.c @@ -4575,7 +4575,8 @@ static int tm_query_info_copy(tm_queue_info_t *queue_info, uint32_t query_flags, odp_tm_query_info_t *info) { - tm_queue_thresholds_t *threshold_params; + if ((query_flags & ODP_TM_QUERY_THRESHOLDS) && !queue_info->threshold_params) + return -1; memset(info, 0, sizeof(odp_tm_query_info_t)); info->total_pkt_cnt = @@ -4587,9 +4588,7 @@ static int tm_query_info_copy(tm_queue_info_t *queue_info, info->approx_byte_cnt = 0; if (query_flags & ODP_TM_QUERY_THRESHOLDS) { - threshold_params = queue_info->threshold_params; - if (!threshold_params) - return -1; + tm_queue_thresholds_t *threshold_params = queue_info->threshold_params; info->max_pkt_cnt = threshold_params->max_pkts; info->max_byte_cnt = threshold_params->max_bytes; @@ -4722,6 +4721,41 @@ void odp_tm_stats_print(odp_tm_t odp_tm) } } +uint64_t odp_tm_to_u64(odp_tm_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_queue_to_u64(odp_tm_queue_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_node_to_u64(odp_tm_node_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_shaper_to_u64(odp_tm_shaper_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_sched_to_u64(odp_tm_sched_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_threshold_to_u64(odp_tm_threshold_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_wred_to_u64(odp_tm_wred_t hdl) +{ + return _odp_pri(hdl); +} + int _odp_tm_init_global(void) { odp_shm_t shm; diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c index 18f583a65..7aee73dc1 100644 --- a/platform/linux-generic/pktio/dpdk.c +++ b/platform/linux-generic/pktio/dpdk.c @@ -1,5 +1,5 @@ /* Copyright (c) 2016-2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -2056,8 +2056,63 @@ static int dpdk_link_status(pktio_entry_t *pktio_entry) memset(&link, 0, sizeof(struct rte_eth_link)); rte_eth_link_get_nowait(pkt_priv(pktio_entry)->port_id, &link); + if (link.link_status) + return ODP_PKTIO_LINK_STATUS_UP; + return ODP_PKTIO_LINK_STATUS_DOWN; +} + +static int dpdk_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + struct rte_eth_link link; + struct rte_eth_fc_conf fc_conf; + uint16_t port_id = pkt_priv(pktio_entry)->port_id; + int ret; - return link.link_status; + memset(&fc_conf, 0, sizeof(struct rte_eth_fc_conf)); + memset(&link, 0, sizeof(struct rte_eth_link)); + + ret = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf); + if (ret && ret != -ENOTSUP) { + ODP_ERR("rte_eth_dev_flow_ctrl_get() failed\n"); + return -1; + } + + memset(info, 0, sizeof(odp_pktio_link_info_t)); + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + if (fc_conf.mode == RTE_FC_RX_PAUSE) { + info->pause_rx = ODP_PKTIO_LINK_PAUSE_ON; + } else if (fc_conf.mode == RTE_FC_TX_PAUSE) { + info->pause_tx = ODP_PKTIO_LINK_PAUSE_ON; + } else if (fc_conf.mode == RTE_FC_FULL) { + info->pause_rx = ODP_PKTIO_LINK_PAUSE_ON; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_ON; + } + + rte_eth_link_get_nowait(port_id, &link); + if (link.link_autoneg == ETH_LINK_AUTONEG) + info->autoneg = ODP_PKTIO_LINK_AUTONEG_ON; + else + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + + if (link.link_duplex == ETH_LINK_FULL_DUPLEX) + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + else + info->duplex = ODP_PKTIO_LINK_DUPLEX_HALF; + + if (link.link_speed == ETH_SPEED_NUM_NONE) + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + else + info->speed = link.link_speed; + + if (link.link_status == ETH_LINK_UP) + info->status = ODP_PKTIO_LINK_STATUS_UP; + else + info->status = ODP_PKTIO_LINK_STATUS_DOWN; + + info->media = "unknown"; + + return 0; } static void stats_convert(const struct rte_eth_stats *rte_stats, @@ -2106,6 +2161,7 @@ const pktio_if_ops_t dpdk_pktio_ops = { .recv = dpdk_recv, .send = dpdk_send, .link_status = dpdk_link_status, + .link_info = dpdk_link_info, .mtu_get = dpdk_frame_maxlen, .promisc_mode_set = dpdk_promisc_mode_set, .promisc_mode_get = dpdk_promisc_mode_get, diff --git a/platform/linux-generic/pktio/ipc.c b/platform/linux-generic/pktio/ipc.c index d63a77b74..34b32ae2c 100644 --- a/platform/linux-generic/pktio/ipc.c +++ b/platform/linux-generic/pktio/ipc.c @@ -900,6 +900,35 @@ static int ipc_stop(pktio_entry_t *pktio_entry) return 0; } +static int ipc_link_status(pktio_entry_t *pktio_entry) +{ + pkt_ipc_t *pktio_ipc = pkt_priv(pktio_entry); + + if (odp_atomic_load_u32(&pktio_ipc->ready)) + return ODP_PKTIO_LINK_STATUS_UP; + return ODP_PKTIO_LINK_STATUS_DOWN; +} + +static int ipc_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + pkt_ipc_t *pktio_ipc = pkt_priv(pktio_entry); + + memset(info, 0, sizeof(odp_pktio_link_info_t)); + + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + info->media = "virtual"; + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + if (odp_atomic_load_u32(&pktio_ipc->ready)) + info->status = ODP_PKTIO_LINK_STATUS_UP; + else + info->status = ODP_PKTIO_LINK_STATUS_DOWN; + + return 0; +} + static int ipc_close(pktio_entry_t *pktio_entry) { pkt_ipc_t *pktio_ipc = pkt_priv(pktio_entry); @@ -947,6 +976,8 @@ const pktio_if_ops_t ipc_pktio_ops = { .send = ipc_pktio_send, .start = ipc_start, .stop = ipc_stop, + .link_status = ipc_link_status, + .link_info = ipc_link_info, .mtu_get = ipc_mtu_get, .promisc_mode_set = NULL, .promisc_mode_get = NULL, diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c index e6d004d43..3de096139 100644 --- a/platform/linux-generic/pktio/loop.c +++ b/platform/linux-generic/pktio/loop.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2013, Nokia Solutions and Networks + * Copyright (c) 2013-2020, Nokia Solutions and Networks * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -367,7 +367,22 @@ static int loopback_mac_addr_get(pktio_entry_t *pktio_entry ODP_UNUSED, static int loopback_link_status(pktio_entry_t *pktio_entry ODP_UNUSED) { /* loopback interfaces are always up */ - return 1; + return ODP_PKTIO_LINK_STATUS_UP; +} + +static int loopback_link_info(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_link_info_t *info) +{ + memset(info, 0, sizeof(odp_pktio_link_info_t)); + + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + info->media = "virtual"; + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + info->status = ODP_PKTIO_LINK_STATUS_UP; + + return 0; } static int loopback_init_capability(pktio_entry_t *pktio_entry) @@ -467,6 +482,7 @@ const pktio_if_ops_t loopback_pktio_ops = { .mac_get = loopback_mac_addr_get, .mac_set = NULL, .link_status = loopback_link_status, + .link_info = loopback_link_info, .capability = loopback_capability, .pktin_ts_res = NULL, .pktin_ts_from_ns = NULL, diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c index e1a5da773..0f608c6f6 100644 --- a/platform/linux-generic/pktio/netmap.c +++ b/platform/linux-generic/pktio/netmap.c @@ -1,5 +1,5 @@ /* Copyright (c) 2015-2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -355,12 +355,33 @@ static int netmap_close(pktio_entry_t *pktio_entry) static int netmap_link_status(pktio_entry_t *pktio_entry) { if (pkt_priv(pktio_entry)->is_virtual) - return 1; + return ODP_PKTIO_LINK_STATUS_UP; return link_status_fd(pkt_priv(pktio_entry)->sockfd, pkt_priv(pktio_entry)->if_name); } +static int netmap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); + + if (pkt_nm->is_virtual) { + memset(info, 0, sizeof(odp_pktio_link_info_t)); + + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + info->media = "virtual"; + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + info->status = ODP_PKTIO_LINK_STATUS_UP; + + return 0; + } + + return link_info_fd(pkt_nm->sockfd, pkt_nm->if_name, info); +} + /** * Wait for netmap link to come up * @@ -1225,6 +1246,7 @@ const pktio_if_ops_t netmap_pktio_ops = { .start = netmap_start, .stop = netmap_stop, .link_status = netmap_link_status, + .link_info = netmap_link_info, .stats = netmap_stats, .stats_reset = netmap_stats_reset, .mtu_get = netmap_mtu_get, diff --git a/platform/linux-generic/pktio/null.c b/platform/linux-generic/pktio/null.c index bb7f85c9b..d739ccafe 100644 --- a/platform/linux-generic/pktio/null.c +++ b/platform/linux-generic/pktio/null.c @@ -154,6 +154,26 @@ static int null_init_global(void) return 0; } +static int null_link_status(pktio_entry_t *pktio_entry ODP_UNUSED) +{ + return ODP_PKTIO_LINK_STATUS_UP; +} + +static int null_link_info(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_link_info_t *info) +{ + memset(info, 0, sizeof(odp_pktio_link_info_t)); + + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + info->media = "virtual"; + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + info->status = ODP_PKTIO_LINK_STATUS_UP; + + return 0; +} + const pktio_if_ops_t null_pktio_ops = { .name = "null", .print = NULL, @@ -179,4 +199,6 @@ const pktio_if_ops_t null_pktio_ops = { .config = NULL, .input_queues_config = null_inqueues_config, .output_queues_config = null_outqueues_config, + .link_status = null_link_status, + .link_info = null_link_info }; diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c index 6ef998717..262528abc 100644 --- a/platform/linux-generic/pktio/pcap.c +++ b/platform/linux-generic/pktio/pcap.c @@ -444,6 +444,26 @@ static int pcapif_init_global(void) return 0; } +static int pcapif_link_status(pktio_entry_t *pktio_entry ODP_UNUSED) +{ + return ODP_PKTIO_LINK_STATUS_UP; +} + +static int pcapif_link_info(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_link_info_t *info) +{ + memset(info, 0, sizeof(odp_pktio_link_info_t)); + + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + info->media = "virtual"; + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + info->status = ODP_PKTIO_LINK_STATUS_UP; + + return 0; +} + const pktio_if_ops_t pcap_pktio_ops = { .name = "pcap", .print = NULL, @@ -466,4 +486,6 @@ const pktio_if_ops_t pcap_pktio_ops = { .config = NULL, .input_queues_config = NULL, .output_queues_config = NULL, + .link_status = pcapif_link_status, + .link_info = pcapif_link_info }; diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c index d148edf03..4776b83f9 100644 --- a/platform/linux-generic/pktio/socket.c +++ b/platform/linux-generic/pktio/socket.c @@ -493,6 +493,11 @@ static int sock_link_status(pktio_entry_t *pktio_entry) pktio_entry->s.name); } +static int sock_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + return link_info_fd(pkt_priv(pktio_entry)->sockfd, pktio_entry->s.name, info); +} + static int sock_capability(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_capability_t *capa) { @@ -566,6 +571,7 @@ const pktio_if_ops_t sock_mmsg_pktio_ops = { .mac_get = sock_mac_addr_get, .mac_set = NULL, .link_status = sock_link_status, + .link_info = sock_link_info, .capability = sock_capability, .pktin_ts_res = NULL, .pktin_ts_from_ns = NULL, diff --git a/platform/linux-generic/pktio/socket_common.c b/platform/linux-generic/pktio/socket_common.c index 4fbf2f041..2eb3b4001 100644 --- a/platform/linux-generic/pktio/socket_common.c +++ b/platform/linux-generic/pktio/socket_common.c @@ -1,5 +1,5 @@ /* Copyright (c) 2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -14,7 +14,9 @@ #include <sys/types.h> #include <sys/ioctl.h> #include <net/if.h> +#include <linux/ethtool.h> #include <linux/if_packet.h> +#include <linux/sockios.h> #include <errno.h> #include <odp_debug_internal.h> #include <odp_errno_define.h> @@ -155,8 +157,141 @@ int link_status_fd(int fd, const char *name) __odp_errno = errno; ODP_DBG("ioctl(SIOCGIFFLAGS): %s: \"%s\".\n", strerror(errno), ifr.ifr_name); + return ODP_PKTIO_LINK_STATUS_UNKNOWN; + } + + if (ifr.ifr_flags & IFF_RUNNING) + return ODP_PKTIO_LINK_STATUS_UP; + return ODP_PKTIO_LINK_STATUS_DOWN; +} + +int link_info_fd(int fd, const char *name, odp_pktio_link_info_t *info) +{ + struct ethtool_link_settings hcmd = {.cmd = ETHTOOL_GLINKSETTINGS}; + struct ethtool_link_settings *ecmd; + struct ethtool_pauseparam pcmd = {.cmd = ETHTOOL_GPAUSEPARAM}; + struct ifreq ifr; + int status; + + status = link_status_fd(fd, name); + if (status < 0) + return -1; + + snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", name); + + /* Link pause status */ + ifr.ifr_data = (void *)&pcmd; + if (ioctl(fd, SIOCETHTOOL, &ifr) && errno != EOPNOTSUPP) { + __odp_errno = errno; + ODP_ERR("ioctl(SIOCETHTOOL): %s: \"%s\".\n", strerror(errno), + ifr.ifr_name); + return -1; + } + + /* Try to perform handshake and fall back to old API if failed */ + ifr.ifr_data = (void *)&hcmd; + if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) { + struct ethtool_cmd ecmd_old = {.cmd = ETHTOOL_GSET}; + + ifr.ifr_data = (void *)&ecmd_old; + if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) { + __odp_errno = errno; + ODP_ERR("ioctl(SIOCETHTOOL): %s: \"%s\".\n", strerror(errno), ifr.ifr_name); + return -1; + } + + memset(info, 0, sizeof(odp_pktio_link_info_t)); + info->speed = ethtool_cmd_speed(&ecmd_old); + if (info->speed == (uint32_t)SPEED_UNKNOWN) + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + + if (ecmd_old.autoneg == AUTONEG_ENABLE) + info->autoneg = ODP_PKTIO_LINK_AUTONEG_ON; + else if (ecmd_old.autoneg == AUTONEG_DISABLE) + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + else + info->autoneg = ODP_PKTIO_LINK_AUTONEG_UNKNOWN; + + if (ecmd_old.duplex == DUPLEX_HALF) + info->duplex = ODP_PKTIO_LINK_DUPLEX_HALF; + else if (ecmd_old.duplex == DUPLEX_FULL) + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + else + info->duplex = ODP_PKTIO_LINK_DUPLEX_UNKNOWN; + + info->pause_rx = pcmd.rx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = pcmd.tx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF; + + if (ecmd_old.port == PORT_TP) + info->media = "copper"; + else if (ecmd_old.port == PORT_FIBRE) + info->media = "fiber"; + else if (ecmd_old.port == PORT_OTHER) + info->media = "other"; + else + info->media = "unknown"; + + info->status = status; + + return 0; + } + + if (hcmd.link_mode_masks_nwords >= 0 || hcmd.cmd != ETHTOOL_GLINKSETTINGS) { + ODP_ERR("ETHTOOL_GLINKSETTINGS handshake failed\n"); + return -1; + } + /* Absolute value indicates kernel recommended 'link_mode_masks_nwords' value. */ + hcmd.link_mode_masks_nwords = -hcmd.link_mode_masks_nwords; + + /* Reserve space for the three bitmasks (map_supported, map_advertising, map_lp_advertising) + * at the end of struct ethtool_link_settings. 'link_mode_masks_nwords' defines the bitmask + * length in 32-bit words. */ + uint8_t ODP_ALIGNED_CACHE data[offsetof(struct ethtool_link_settings, link_mode_masks) + + (3 * sizeof(uint32_t) * hcmd.link_mode_masks_nwords)]; + + ecmd = (void *)data; + *ecmd = hcmd; + ifr.ifr_data = (void *)ecmd; + if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) { + __odp_errno = errno; + ODP_ERR("ioctl(SIOCETHTOOL): %s: \"%s\".\n", strerror(errno), + ifr.ifr_name); return -1; } - return !!(ifr.ifr_flags & IFF_RUNNING); + memset(info, 0, sizeof(odp_pktio_link_info_t)); + if (ecmd->speed == (uint32_t)SPEED_UNKNOWN) + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + else + info->speed = ecmd->speed; + + if (ecmd->autoneg == AUTONEG_ENABLE) + info->autoneg = ODP_PKTIO_LINK_AUTONEG_ON; + else if (ecmd->autoneg == AUTONEG_DISABLE) + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + else + info->autoneg = ODP_PKTIO_LINK_AUTONEG_UNKNOWN; + + if (ecmd->duplex == DUPLEX_HALF) + info->duplex = ODP_PKTIO_LINK_DUPLEX_HALF; + else if (ecmd->duplex == DUPLEX_FULL) + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + else + info->duplex = ODP_PKTIO_LINK_DUPLEX_UNKNOWN; + + info->pause_rx = pcmd.rx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = pcmd.tx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF; + + if (ecmd->port == PORT_TP) + info->media = "copper"; + else if (ecmd->port == PORT_FIBRE) + info->media = "fiber"; + else if (ecmd->port == PORT_OTHER) + info->media = "other"; + else + info->media = "unknown"; + + info->status = status; + + return 0; } diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c index bf1cbad81..d0d37636d 100644 --- a/platform/linux-generic/pktio/socket_mmap.c +++ b/platform/linux-generic/pktio/socket_mmap.c @@ -784,6 +784,11 @@ static int sock_mmap_link_status(pktio_entry_t *pktio_entry) pktio_entry->s.name); } +static int sock_mmap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + return link_info_fd(pkt_priv(pktio_entry)->sockfd, pktio_entry->s.name, info); +} + static int sock_mmap_capability(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_capability_t *capa) { @@ -860,6 +865,7 @@ const pktio_if_ops_t sock_mmap_pktio_ops = { .mac_get = sock_mmap_mac_addr_get, .mac_set = NULL, .link_status = sock_mmap_link_status, + .link_info = sock_mmap_link_info, .capability = sock_mmap_capability, .pktin_ts_res = NULL, .pktin_ts_from_ns = NULL, diff --git a/platform/linux-generic/pktio/tap.c b/platform/linux-generic/pktio/tap.c index db5c701b2..13a9feaf8 100644 --- a/platform/linux-generic/pktio/tap.c +++ b/platform/linux-generic/pktio/tap.c @@ -467,6 +467,11 @@ static int tap_link_status(pktio_entry_t *pktio_entry) pktio_entry->s.name + 4); } +static int tap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + return link_info_fd(pkt_priv(pktio_entry)->skfd, pktio_entry->s.name + 4, info); +} + static int tap_capability(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_capability_t *capa) { @@ -501,6 +506,7 @@ const pktio_if_ops_t tap_pktio_ops = { .mac_get = tap_mac_addr_get, .mac_set = tap_mac_addr_set, .link_status = tap_link_status, + .link_info = tap_link_info, .capability = tap_capability, .pktin_ts_res = NULL, .pktin_ts_from_ns = NULL, diff --git a/platform/linux-generic/test/pktio_ipc/ipc_common.c b/platform/linux-generic/test/pktio_ipc/ipc_common.c index b064177bc..655cd80d5 100644 --- a/platform/linux-generic/test/pktio_ipc/ipc_common.c +++ b/platform/linux-generic/test/pktio_ipc/ipc_common.c @@ -22,6 +22,7 @@ int ipc_odp_packet_send_or_free(odp_pktio_t pktio, odp_pktout_queue_t pktout; int i; + memset(&pktout, 0, sizeof(pktout)); start_time = odp_time_local(); wait = odp_time_local_from_ns(ODP_TIME_SEC_IN_NS); end_time = odp_time_sum(start_time, wait); diff --git a/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c index 0d64e94ba..9d4f91341 100644 --- a/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c +++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c @@ -73,6 +73,7 @@ static int ipc_second_process(int master_pid) return -1; } + memset(&pktin, 0, sizeof(pktin)); /* not needed but makes GCC happy */ if (odp_pktin_queue(ipc_pktio, &pktin, 1) != 1) { odp_pool_destroy(pool); ODPH_ERR("no input queue\n"); diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index a0d189722..a8976b1e5 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1,9 +1,11 @@ #!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0 +# # (c) 2001, Dave Jones. (the file handling bit) # (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit) # (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite) # (c) 2008-2010 Andy Whitcroft <apw@canonical.com> -# Licensed under the terms of the GNU GPL License version 2 +# (c) 2010-2018 Joe Perches <joe@perches.com> use strict; use warnings; @@ -11,6 +13,7 @@ use POSIX; use File::Basename; use Cwd 'abs_path'; use Term::ANSIColor qw(:constants); +use Encode qw(decode encode); my $P = $0; my $D = dirname(abs_path($P)); @@ -48,7 +51,7 @@ my %ignore_type = (); my @ignore = (); my $help = 0; my $configuration_file = ".checkpatch.conf"; -my $max_line_length = 80; +my $max_line_length = 100; my $ignore_perl_version = 0; my $minimum_perl_version = 5.10.0; my $min_conf_desc_length = 4; @@ -58,7 +61,10 @@ my $codespellfile = "/usr/share/codespell/dictionary.txt"; my $conststructsfile = "$D/const_structs.checkpatch"; my $typedefsfile = ""; my $color = "auto"; -my $allow_c99_comments = 1; +my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE +# git output parsing needs US English output, so first set backtick child process LANGUAGE +my $git_command ='export LANGUAGE=en_US.UTF-8; git'; +my $tabsize = 8; sub help { my ($exitcode) = @_; @@ -91,8 +97,11 @@ Options: --types TYPE(,TYPE2...) show only these comma separated message types --ignore TYPE(,TYPE2...) ignore various comma separated message types --show-types show the specific message type in the output - --max-line-length=n set the maximum line length, if exceeded, warn + --max-line-length=n set the maximum line length, (default $max_line_length) + if exceeded, warn on patches + requires --strict for use with --file --min-conf-desc-length=n set the min description length, if shorter, warn + --tab-size=n set the number of spaces for tab (default $tabsize) --root=PATH PATH to the kernel tree root --no-summary suppress the per-file summary --mailback only produce a report in case of warnings/errors @@ -210,6 +219,7 @@ GetOptions( 'list-types!' => \$list_types, 'max-line-length=i' => \$max_line_length, 'min-conf-desc-length=i' => \$min_conf_desc_length, + 'tab-size=i' => \$tabsize, 'root=s' => \$root, 'summary!' => \$summary, 'mailback!' => \$mailback, @@ -236,13 +246,15 @@ list_types(0) if ($list_types); $fix = 1 if ($fix_inplace); $check_orig = $check; +die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix)); + my $exit = 0; +my $perl_version_ok = 1; if ($^V && $^V lt $minimum_perl_version) { + $perl_version_ok = 0; printf "$P: requires at least perl version %vd\n", $minimum_perl_version; - if (!$ignore_perl_version) { - exit(1); - } + exit(1) if (!$ignore_perl_version); } #if no filenames are given, push '-' to read patch from stdin @@ -259,9 +271,12 @@ if ($color =~ /^[01]$/) { } elsif ($color =~ /^auto$/i) { $color = (-t STDOUT); } else { - die "Invalid color mode: $color\n"; + die "$P: Invalid color mode: $color\n"; } +# skip TAB size 1 to avoid additional checks on $tabsize - 1 +die "$P: Invalid TAB size: $tabsize\n" if ($tabsize < 2); + sub hash_save_array_words { my ($hashRef, $arrayRef) = @_; @@ -344,9 +359,10 @@ our $Sparse = qr{ __force| __iomem| __must_check| - __init_refok| __kprobes| __ref| + __refconst| + __refdata| __rcu| __private }x; @@ -376,6 +392,7 @@ our $Attribute = qr{ __noclone| __deprecated| __read_mostly| + __ro_after_init| __kprobes| $InitAttribute| ____cacheline_aligned| @@ -458,15 +475,22 @@ our $logFunctions = qr{(?x: WARN(?:_RATELIMIT|_ONCE|)| panic| MODULE_[A-Z_]+| - seq_vprintf|seq_printf|seq_puts| - ODP_ASSERT|ODP_DBG|ODP_ERR|ODP_ABORT|ODP_LOG|ODP_PRINT| - EXAMPLE_DBG|EXAMPLE_ERR|EXAMPLE_ABORT| - LOG_DBG|LOG_ERR|LOG_ABORT| - printf + seq_vprintf|seq_printf|seq_puts +)}; + +our $allocFunctions = qr{(?x: + (?:(?:devm_)? + (?:kv|k|v)[czm]alloc(?:_node|_array)? | + kstrdup(?:_const)? | + kmemdup(?:_nul)?) | + (?:\w+)?alloc_skb(?:_ip_align)? | + # dev_alloc_skb/netdev_alloc_skb, et al + dma_alloc_coherent )}; our $signature_tags = qr{(?xi: Signed-off-by:| + Co-developed-by:| Acked-by:| Tested-by:| Reviewed-by:| @@ -572,6 +596,27 @@ foreach my $entry (@mode_permission_funcs) { } $mode_perms_search = "(?:${mode_perms_search})"; +our %deprecated_apis = ( + "synchronize_rcu_bh" => "synchronize_rcu", + "synchronize_rcu_bh_expedited" => "synchronize_rcu_expedited", + "call_rcu_bh" => "call_rcu", + "rcu_barrier_bh" => "rcu_barrier", + "synchronize_sched" => "synchronize_rcu", + "synchronize_sched_expedited" => "synchronize_rcu_expedited", + "call_rcu_sched" => "call_rcu", + "rcu_barrier_sched" => "rcu_barrier", + "get_state_synchronize_sched" => "get_state_synchronize_rcu", + "cond_synchronize_sched" => "cond_synchronize_rcu", +); + +#Create a search pattern for all these strings to speed up a loop below +our $deprecated_apis_search = ""; +foreach my $entry (keys %deprecated_apis) { + $deprecated_apis_search .= '|' if ($deprecated_apis_search ne ""); + $deprecated_apis_search .= $entry; +} +$deprecated_apis_search = "(?:${deprecated_apis_search})"; + our $mode_perms_world_writable = qr{ S_IWUGO | S_IWOTH | @@ -769,12 +814,12 @@ sub build_types { }x; $Type = qr{ $NonptrType - (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+)? + (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+){0,4} (?:\s+$Inline|\s+$Modifier)* }x; $TypeMisordered = qr{ $NonptrTypeMisordered - (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+)? + (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+){0,4} (?:\s+$Inline|\s+$Modifier)* }x; $Declare = qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type}; @@ -795,7 +840,8 @@ our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)}; our $declaration_macros = qr{(?x: (?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(| (?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(| - (?:$Storage\s+)?${Type}\s+uninitialized_var\s*\( + (?:$Storage\s+)?${Type}\s+uninitialized_var\s*\(| + (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\( )}; sub deparenthesize { @@ -838,14 +884,29 @@ sub seed_camelcase_file { } } +our %maintained_status = (); + sub is_maintained_obsolete { my ($filename) = @_; return 0 if (!$tree || !(-e "$root/scripts/get_maintainer.pl")); - my $status = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`; + if (!exists($maintained_status{$filename})) { + $maintained_status{$filename} = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`; + } - return $status =~ /obsolete/i; + return $maintained_status{$filename} =~ /obsolete/i; +} + +sub is_SPDX_License_valid { + my ($license) = @_; + + return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$root/.git")); + + my $root_path = abs_path($root); + my $status = `cd "$root_path"; echo "$license" | python scripts/spdxcheck.py -`; + return 0 if ($status ne ""); + return 1; } my $camelcase_seeded = 0; @@ -859,7 +920,7 @@ sub seed_camelcase_includes { $camelcase_seeded = 1; if (-e ".git") { - my $git_last_include_commit = `git log --no-merges --pretty=format:"%h%n" -1 -- include`; + my $git_last_include_commit = `${git_command} log --no-merges --pretty=format:"%h%n" -1 -- include`; chomp $git_last_include_commit; $camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit"; } else { @@ -887,7 +948,7 @@ sub seed_camelcase_includes { } if (-e ".git") { - $files = `git ls-files "include/*.h"`; + $files = `${git_command} ls-files "include/*.h"`; @include_files = split('\n', $files); } @@ -911,13 +972,13 @@ sub git_commit_info { return ($id, $desc) if ((which("git") eq "") || !(-e ".git")); - my $output = `git log --no-color --format='%H %s' -1 $commit 2>&1`; + my $output = `${git_command} log --no-color --format='%H %s' -1 $commit 2>&1`; $output =~ s/^\s*//gm; my @lines = split("\n", $output); return ($id, $desc) if ($#lines < 0); - if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous\./) { + if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous/) { # Maybe one day convert this block of bash into something that returns # all matching commit ids, but it's very slow... # @@ -961,7 +1022,7 @@ if ($git) { } else { $git_range = "-1 $commit_expr"; } - my $lines = `git log --no-color --no-merges --pretty=format:'%H %s' $git_range`; + my $lines = `${git_command} log --no-color --no-merges --pretty=format:'%H %s' $git_range`; foreach my $line (split(/\n/, $lines)) { $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/; next if (!defined($1) || !defined($2)); @@ -976,6 +1037,7 @@ if ($git) { } my $vname; +$allow_c99_comments = !defined $ignore_type{"C99_COMMENT_TOLERANCE"}; for my $filename (@ARGV) { my $FILE; if ($git) { @@ -1000,6 +1062,7 @@ for my $filename (@ARGV) { while (<$FILE>) { chomp; push(@rawlines, $_); + $vname = qq("$1") if ($filename eq '-' && $_ =~ m/^Subject:\s+(.+)/i); } close($FILE); @@ -1027,11 +1090,11 @@ if (!$quiet) { hash_show_words(\%use_type, "Used"); hash_show_words(\%ignore_type, "Ignored"); - if ($^V lt 5.10.0) { + if (!$perl_version_ok) { print << "EOM" NOTE: perl $^V is not modern enough to detect all possible issues. - An upgrade to at least perl v5.10.0 is suggested. + An upgrade to at least perl $minimum_perl_version is suggested. EOM } if ($exit) { @@ -1066,6 +1129,7 @@ sub parse_email { my ($formatted_email) = @_; my $name = ""; + my $name_comment = ""; my $address = ""; my $comment = ""; @@ -1079,7 +1143,7 @@ sub parse_email { } elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) { $address = $1; $comment = $2 if defined $2; - $formatted_email =~ s/$address.*$//; + $formatted_email =~ s/\Q$address\E.*$//; $name = $formatted_email; $name = trim($name); $name =~ s/^\"|\"$//g; @@ -1098,6 +1162,10 @@ sub parse_email { $name = trim($name); $name =~ s/^\"|\"$//g; + $name =~ s/(\s*\([^\)]+\))\s*//; + if (defined($1)) { + $name_comment = trim($1); + } $address = trim($address); $address =~ s/^\<|\>$//g; @@ -1106,7 +1174,7 @@ sub parse_email { $name = "\"$name\""; } - return ($name, $address, $comment); + return ($name, $name_comment, $address, $comment); } sub format_email { @@ -1132,6 +1200,23 @@ sub format_email { return $formatted_email; } +sub reformat_email { + my ($email) = @_; + + my ($email_name, $name_comment, $email_address, $comment) = parse_email($email); + return format_email($email_name, $email_address); +} + +sub same_email_addresses { + my ($email1, $email2) = @_; + + my ($email1_name, $name1_comment, $email1_address, $comment1) = parse_email($email1); + my ($email2_name, $name2_comment, $email2_address, $comment2) = parse_email($email2); + + return $email1_name eq $email2_name && + $email1_address eq $email2_address; +} + sub which { my ($bin) = @_; @@ -1165,7 +1250,7 @@ sub expand_tabs { if ($c eq "\t") { $res .= ' '; $n++; - for (; ($n % 8) != 0; $n++) { + for (; ($n % $tabsize) != 0; $n++) { $res .= ' '; } next; @@ -1221,7 +1306,7 @@ sub sanitise_line { for ($off = 1; $off < length($line); $off++) { $c = substr($line, $off, 1); - # Comments we are wacking completly including the begin + # Comments we are whacking completely including the begin # and end, all to $;. if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { $sanitise_quote = '*/'; @@ -1301,6 +1386,7 @@ sub sanitise_line { sub get_quoted_string { my ($line, $rawline) = @_; + return "" if (!defined($line) || !defined($rawline)); return "" if ($line !~ m/($String)/g); return substr($rawline, $-[0], $+[0] - $-[0]); } @@ -1593,8 +1679,16 @@ sub ctx_statement_level { sub ctx_locate_comment { my ($first_line, $end_line) = @_; + # If c99 comment on the current line, or the line before or after + my ($current_comment) = ($rawlines[$end_line - 1] =~ m@^\+.*(//.*$)@); + return $current_comment if (defined $current_comment); + ($current_comment) = ($rawlines[$end_line - 2] =~ m@^[\+ ].*(//.*$)@); + return $current_comment if (defined $current_comment); + ($current_comment) = ($rawlines[$end_line] =~ m@^[\+ ].*(//.*$)@); + return $current_comment if (defined $current_comment); + # Catch a comment on the end of the line itself. - my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); + ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); return $current_comment if (defined $current_comment); # Look through the context and try and figure out if there is a @@ -1648,6 +1742,28 @@ sub raw_line { return $line; } +sub get_stat_real { + my ($linenr, $lc) = @_; + + my $stat_real = raw_line($linenr, 0); + for (my $count = $linenr + 1; $count <= $lc; $count++) { + $stat_real = $stat_real . "\n" . raw_line($count, 0); + } + + return $stat_real; +} + +sub get_stat_here { + my ($linenr, $cnt, $here) = @_; + + my $herectx = $here . "\n"; + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + + return $herectx; +} + sub cat_vet { my ($vet) = @_; my ($res, $coded); @@ -2155,7 +2271,7 @@ sub string_find_replace { sub tabify { my ($leading) = @_; - my $source_indent = 8; + my $source_indent = $tabsize; my $max_spaces_before_tab = $source_indent - 1; my $spaces_to_tab = " " x $source_indent; @@ -2197,6 +2313,19 @@ sub pos_last_openparen { return length(expand_tabs(substr($line, 0, $last_openparen))) + 1; } +sub get_raw_comment { + my ($line, $rawline) = @_; + my $comment = ''; + + for my $i (0 .. (length($line) - 1)) { + if (substr($line, $i, 1) eq "$;") { + $comment .= substr($rawline, $i, 1); + } + } + + return $comment; +} + sub process { my $filename = shift; @@ -2213,14 +2342,19 @@ sub process { our $clean = 1; my $signoff = 0; + my $author = ''; + my $authorsignoff = 0; my $is_patch = 0; + my $is_binding_patch = -1; my $in_header_lines = $file ? 0 : 1; my $in_commit_log = 0; #Scanning lines before patch + my $has_patch_separator = 0; #Found a --- line my $has_commit_log = 0; #Encountered lines before patch + my $commit_log_lines = 0; #Number of commit log lines my $commit_log_possible_stack_dump = 0; my $commit_log_long_line = 0; my $commit_log_has_diff = 0; - my $reported_maintainer_file = 1; # No MAINTAINTERS so silence warning + my $reported_maintainer_file = 1; # ODP has no MAINTAINERS file my $non_utf8_charset = 0; my $last_blank_line = 0; @@ -2261,6 +2395,8 @@ sub process { my $camelcase_file_seeded = 0; + my $checklicenseline = 1; + sanitise_line_reset(); my $line; foreach my $rawline (@rawlines) { @@ -2352,6 +2488,15 @@ sub process { $sline =~ s/$;/ /g; #with comments as spaces my $rawline = $rawlines[$linenr - 1]; + my $raw_comment = get_raw_comment($line, $rawline); + +# check if it's a mode change, rename or start of a patch + if (!$in_commit_log && + ($line =~ /^ mode change [0-7]+ => [0-7]+ \S+\s*$/ || + ($line =~ /^rename (?:from|to) \S+\s*$/ || + $line =~ /^diff --git a\/[\w\/\.\_\-]+ b\/\S+\s*$/))) { + $is_patch = 1; + } #extract the line range in the file after the patch is applied if (!$in_commit_log && @@ -2452,6 +2597,20 @@ sub process { } else { $check = $check_orig; } + $checklicenseline = 1; + + if ($realfile !~ /^MAINTAINERS/) { + my $last_binding_patch = $is_binding_patch; + + $is_binding_patch = () = $realfile =~ m@^(?:Documentation/devicetree/|include/dt-bindings/)@; + + if (($last_binding_patch != -1) && + ($last_binding_patch ^ $is_binding_patch)) { + WARN("DT_SPLIT_BINDING_PATCH", + "DT binding docs and includes should be a separate patch. See: Documentation/devicetree/bindings/submitting-patches.rst\n"); + } + } + next; } @@ -2463,6 +2622,18 @@ sub process { $cnt_lines++ if ($realcnt != 0); +# Verify the existence of a commit log if appropriate +# 2 is used because a $signature is counted in $commit_log_lines + if ($in_commit_log) { + if ($line !~ /^\s*$/) { + $commit_log_lines++; #could be a $signature + } + } elsif ($has_commit_log && $commit_log_lines < 2) { + WARN("COMMIT_MESSAGE", + "Missing commit description - Add an appropriate one\n"); + $commit_log_lines = 2; #warn only once + } + # Check if the commit log has what seems like a diff which can confuse patch if ($in_commit_log && !$commit_log_has_diff && (($line =~ m@^\s+diff\b.*a/[\w/]+@ && @@ -2484,10 +2655,29 @@ sub process { } } +# Check the patch for a From: + if (decode("MIME-Header", $line) =~ /^From:\s*(.*)/) { + $author = $1; + $author = encode("utf8", $author) if ($line =~ /=\?utf-8\?/i); + $author =~ s/"//g; + $author = reformat_email($author); + } + # Check the patch for a signoff: - if ($line =~ /^\s*signed-off-by:/i) { + if ($line =~ /^\s*signed-off-by:\s*(.*)/i) { $signoff++; - #$in_commit_log = 0; + $in_commit_log = 0; + if ($author ne '') { + if (same_email_addresses($1, $author)) { + $authorsignoff = 1; + } + } + } + +# Check for patch separator + if ($line =~ /^---$/) { + $has_patch_separator = 1; + $in_commit_log = 0; } # Check if MAINTAINERS is being updated. If so, there's probably no need to @@ -2497,7 +2687,7 @@ sub process { } # Check signature styles - if (!$in_header_lines && $in_commit_log && + if (!$in_header_lines && $line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) { my $space_before = $1; my $sign_off = $2; @@ -2535,7 +2725,7 @@ sub process { } } - my ($email_name, $email_address, $comment) = parse_email($email); + my ($email_name, $name_comment, $email_address, $comment) = parse_email($email); my $suggested_email = format_email(($email_name, $email_address)); if ($suggested_email eq "") { ERROR("BAD_SIGN_OFF", @@ -2546,9 +2736,7 @@ sub process { $dequoted =~ s/" </ </; # Don't force email to have quotes # Allow just an angle bracketed address - if ("$dequoted$comment" ne $email && - "<$email_address>$comment" ne $email && - "$suggested_email$comment" ne $email) { + if (!same_email_addresses($email, $suggested_email)) { WARN("BAD_SIGN_OFF", "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr); } @@ -2564,6 +2752,24 @@ sub process { } else { $signatures{$sig_nospace} = 1; } + +# Check Co-developed-by: immediately followed by Signed-off-by: with same name and email + if ($sign_off =~ /^co-developed-by:$/i) { + if ($email eq $author) { + WARN("BAD_SIGN_OFF", + "Co-developed-by: should not be used to attribute nominal patch author '$author'\n" . "$here\n" . $rawline); + } + if (!defined $lines[$linenr]) { + WARN("BAD_SIGN_OFF", + "Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline); + } elsif ($rawlines[$linenr] !~ /^\s*signed-off-by:\s*(.*)/i) { + WARN("BAD_SIGN_OFF", + "Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]); + } elsif ($1 ne $email) { + WARN("BAD_SIGN_OFF", + "Co-developed-by and Signed-off-by: name/email do not match \n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]); + } + } } # Check email subject for common tools that don't need to be mentioned @@ -2573,16 +2779,10 @@ sub process { "A patch subject line should describe the change not the tool that found it\n" . $herecurr); } -# Check for old stable address - if ($line =~ /^\s*cc:\s*.*<?\bstable\@kernel\.org\b>?.*$/i) { - ERROR("STABLE_ADDRESS", - "The 'stable' address should be 'stable\@vger.kernel.org'\n" . $herecurr); - } - -# Check for unwanted Gerrit info - if ($in_commit_log && $line =~ /^\s*change-id:/i) { +# Check for Gerrit Change-Ids not in any patch context + if ($realfile eq '' && !$has_patch_separator && $line =~ /^\s*change-id:/i) { ERROR("GERRIT_CHANGE_ID", - "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr); + "Remove Gerrit Change-Id's before submitting upstream\n" . $herecurr); } # Check if the commit log is in a possible stack dump @@ -2590,8 +2790,10 @@ sub process { ($line =~ /^\s*(?:WARNING:|BUG:)/ || $line =~ /^\s*\[\s*\d+\.\d{6,6}\s*\]/ || # timestamp - $line =~ /^\s*\[\<[0-9a-fA-F]{8,}\>\]/)) { - # stack dump address + $line =~ /^\s*\[\<[0-9a-fA-F]{8,}\>\]/) || + $line =~ /^(?:\s+\w+:\s+[0-9a-fA-F]+){3,3}/ || + $line =~ /^\s*\#\d+\s*\[[0-9a-fA-F]+\]\s*\w+ at [0-9a-fA-F]+/) { + # stack dump address styles $commit_log_possible_stack_dump = 1; } @@ -2618,7 +2820,7 @@ sub process { # Check for git id commit length and improperly formed commit descriptions if ($in_commit_log && !$commit_log_possible_stack_dump && - $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink):/i && + $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink|base-commit):/i && $line !~ /^This reverts commit [0-9a-f]{7,40}/ && ($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i || ($line =~ /(?:\s|^)[0-9a-f]{12,40}(?:[\s"'\(\[]|$)/i && @@ -2687,6 +2889,14 @@ sub process { "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); } +# Check for adding new DT bindings not in schema format + if (!$in_commit_log && + ($line =~ /^new file mode\s*\d+\s*$/) && + ($realfile =~ m@^Documentation/devicetree/bindings/.*\.txt$@)) { + WARN("DT_SCHEMA_BINDING_PATCH", + "DT bindings should be in DT schema format. See: Documentation/devicetree/writing-schema.rst\n"); + } + # Check for wrappage within a valid hunk of the file if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { ERROR("CORRUPTED_PATCH", @@ -2763,6 +2973,17 @@ sub process { } } +# check for invalid commit id + if ($in_commit_log && $line =~ /(^fixes:|\bcommit)\s+([0-9a-f]{6,40})\b/i) { + my $id; + my $description; + ($id, $description) = git_commit_info($2, undef, undef); + if (!defined($id)) { + WARN("UNKNOWN_COMMIT_ID", + "Unknown commit id '$2', maybe rebased or not pulled?\n" . $herecurr); + } + } + # ignore non-hunk lines and lines being removed next if (!$hunk_line || $line =~ /^-/); @@ -2801,7 +3022,10 @@ sub process { # Only applies when adding the entry originally, after that we do not have # sufficient context to determine whether it is indeed long enough. if ($realfile =~ /Kconfig/ && - $line =~ /^\+\s*config\s+/) { + # 'choice' is usually the last thing on the line (though + # Kconfig supports named choices), so use a word boundary + # (\b) rather than a whitespace character (\s) + $line =~ /^\+\s*(?:config|menuconfig|choice)\b/) { my $length = 0; my $cnt = $realcnt; my $ln = $linenr + 1; @@ -2816,9 +3040,13 @@ sub process { next if ($f =~ /^-/); last if (!$file && $f =~ /^\@\@/); - if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate)\s*\"/) { + if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { $is_start = 1; - } elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) { + } elsif ($lines[$ln - 1] =~ /^\+\s*(?:help|---help---)\s*$/) { + if ($lines[$ln - 1] =~ "---help---") { + WARN("CONFIG_DESCRIPTION", + "prefer 'help' over '---help---' for new help texts\n" . $herecurr); + } $length = -1; } @@ -2826,7 +3054,13 @@ sub process { $f =~ s/#.*//; $f =~ s/^\s+//; next if ($f =~ /^$/); - if ($f =~ /^\s*config\s/) { + + # This only checks context lines in the patch + # and so hopefully shouldn't trigger false + # positives, even though some of these are + # common words in help texts + if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice| + if|endif|menu|endmenu|source)\b/x) { $is_end = 1; last; } @@ -2839,14 +3073,43 @@ sub process { #print "is_start<$is_start> is_end<$is_end> length<$length>\n"; } -# check for MAINTAINERS entries that don't have the right form - if ($realfile =~ /^MAINTAINERS$/ && - $rawline =~ /^\+[A-Z]:/ && - $rawline !~ /^\+[A-Z]:\t\S/) { - if (WARN("MAINTAINERS_STYLE", - "MAINTAINERS entries use one tab after TYPE:\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/^(\+[A-Z]):\s*/$1:\t/; +# check MAINTAINERS entries + if ($realfile =~ /^MAINTAINERS$/) { +# check MAINTAINERS entries for the right form + if ($rawline =~ /^\+[A-Z]:/ && + $rawline !~ /^\+[A-Z]:\t\S/) { + if (WARN("MAINTAINERS_STYLE", + "MAINTAINERS entries use one tab after TYPE:\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/^(\+[A-Z]):\s*/$1:\t/; + } + } +# check MAINTAINERS entries for the right ordering too + my $preferred_order = 'MRLSWQBCPTFXNK'; + if ($rawline =~ /^\+[A-Z]:/ && + $prevrawline =~ /^[\+ ][A-Z]:/) { + $rawline =~ /^\+([A-Z]):\s*(.*)/; + my $cur = $1; + my $curval = $2; + $prevrawline =~ /^[\+ ]([A-Z]):\s*(.*)/; + my $prev = $1; + my $prevval = $2; + my $curindex = index($preferred_order, $cur); + my $previndex = index($preferred_order, $prev); + if ($curindex < 0) { + WARN("MAINTAINERS_STYLE", + "Unknown MAINTAINERS entry type: '$cur'\n" . $herecurr); + } else { + if ($previndex >= 0 && $curindex < $previndex) { + WARN("MAINTAINERS_STYLE", + "Misordered MAINTAINERS entry - list '$cur:' before '$prev:'\n" . $hereprev); + } elsif ((($prev eq 'F' && $cur eq 'F') || + ($prev eq 'X' && $cur eq 'X')) && + ($prevval cmp $curval) > 0) { + WARN("MAINTAINERS_STYLE", + "Misordered MAINTAINERS entry - list file patterns in alphabetic order\n" . $hereprev); + } + } } } @@ -2879,7 +3142,7 @@ sub process { my @compats = $rawline =~ /\"([a-zA-Z0-9\-\,\.\+_]+)\"/g; my $dt_path = $root . "/Documentation/devicetree/bindings/"; - my $vp_file = $dt_path . "vendor-prefixes.txt"; + my $vp_file = $dt_path . "vendor-prefixes.yaml"; foreach my $compat (@compats) { my $compat2 = $compat; @@ -2894,7 +3157,7 @@ sub process { next if $compat !~ /^([a-zA-Z0-9\-]+)\,/; my $vendor = $1; - `grep -Eq "^$vendor\\b" $vp_file`; + `grep -Eq "\\"\\^\Q$vendor\E,\\.\\*\\":" $vp_file`; if ( $? >> 8 ) { WARN("UNDOCUMENTED_DT_STRING", "DT compatible string vendor \"$vendor\" appears un-documented -- check $vp_file\n" . $herecurr); @@ -2902,9 +3165,66 @@ sub process { } } +# check for using SPDX license tag at beginning of files + if ($realline == $checklicenseline) { + if ($rawline =~ /^[ \+]\s*\#\!\s*\//) { + $checklicenseline = 2; + } elsif ($rawline =~ /^\+/) { + my $comment = ""; + if ($realfile =~ /\.(h|s|S)$/) { + $comment = '/*'; + } elsif ($realfile =~ /\.(c|dts|dtsi)$/) { + $comment = '//'; + } elsif (($checklicenseline == 2) || $realfile =~ /\.(sh|pl|py|awk|tc|yaml)$/) { + $comment = '#'; + } elsif ($realfile =~ /\.rst$/) { + $comment = '..'; + } + +# check SPDX comment style for .[chsS] files + if ($realfile =~ /\.[chsS]$/ && + $rawline =~ /SPDX-License-Identifier:/ && + $rawline !~ m@^\+\s*\Q$comment\E\s*@) { + WARN("SPDX_LICENSE_TAG", + "Improper SPDX comment style for '$realfile', please use '$comment' instead\n" . $herecurr); + } + + if ($comment !~ /^$/ && + $rawline !~ m@^\+\Q$comment\E SPDX-License-Identifier: @) { + WARN("SPDX_LICENSE_TAG", + "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr); + } elsif ($rawline =~ /(SPDX-License-Identifier: .*)/) { + my $spdx_license = $1; + if (!is_SPDX_License_valid($spdx_license)) { + WARN("SPDX_LICENSE_TAG", + "'$spdx_license' is not supported in LICENSES/...\n" . $herecurr); + } + if ($realfile =~ m@^Documentation/devicetree/bindings/@ && + not $spdx_license =~ /GPL-2\.0.*BSD-2-Clause/) { + my $msg_level = \&WARN; + $msg_level = \&CHK if ($file); + if (&{$msg_level}("SPDX_LICENSE_TAG", + + "DT binding documents should be licensed (GPL-2.0-only OR BSD-2-Clause)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/SPDX-License-Identifier: .*/SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)/; + } + } + } + } + } + # check we are in a valid source file if not then ignore this hunk next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/); +# check for using SPDX-License-Identifier on the wrong line number + if ($realline != $checklicenseline && + $rawline =~ /\bSPDX-License-Identifier:/ && + substr($line, @-, @+ - @-) eq "$;" x (@+ - @-)) { + WARN("SPDX_LICENSE_TAG", + "Misplaced SPDX-License-Identifier tag - use line $checklicenseline instead\n" . $herecurr); + } + # line length limit (with some exclusions) # # There are a few types of lines that may extend beyond $max_line_length: @@ -2962,8 +3282,10 @@ sub process { if ($msg_type ne "" && (show_type("LONG_LINE") || show_type($msg_type))) { - WARN($msg_type, - "line over $max_line_length characters\n" . $herecurr); + my $msg_level = \&WARN; + $msg_level = \&CHK if ($file); + &{$msg_level}($msg_type, + "line length of $length exceeds $max_line_length columns\n" . $herecurr); } } @@ -2973,25 +3295,11 @@ sub process { "adding a line without newline at end of file\n" . $herecurr); } -# Blackfin: use hi/lo macros - if ($realfile =~ m@arch/blackfin/.*\.S$@) { - if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("LO_MACRO", - "use the LO() macro, not (... & 0xFFFF)\n" . $herevet); - } - if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("HI_MACRO", - "use the HI() macro, not (... >> 16)\n" . $herevet); - } - } - # check we are in a valid source file C or perl if not then ignore this hunk next if ($realfile !~ /\.(h|c|pl|dtsi|dts)$/); # at the beginning of a line any tabs must come first and anything -# more than 8 must use tabs. +# more than $tabsize must use tabs. if ($rawline =~ /^\+\s* \t\s*\S/ || $rawline =~ /^\+\s* \s*/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; @@ -3010,12 +3318,18 @@ sub process { "please, no space before tabs\n" . $herevet) && $fix) { while ($fixed[$fixlinenr] =~ - s/(^\+.*) {8,8}\t/$1\t\t/) {} + s/(^\+.*) {$tabsize,$tabsize}\t/$1\t\t/) {} while ($fixed[$fixlinenr] =~ s/(^\+.*) +\t/$1\t/) {} } } +# check for assignments on the start of a line + if ($sline =~ /^\+\s+($Assignment)[^=]/) { + CHK("ASSIGNMENT_CONTINUATIONS", + "Assignment operator '$1' should be on the previous line\n" . $hereprev); + } + # check for && or || at the start of a line if ($rawline =~ /^\+\s*(&&|\|\|)/) { CHK("LOGICAL_CONTINUATIONS", @@ -3023,20 +3337,20 @@ sub process { } # check indentation starts on a tab stop - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$)|$Declare\s*$Ident\s*[;=])/) { my $indent = length($1); - if ($indent % 8) { + if ($indent % $tabsize) { if (WARN("TABSTOP", "Statements should start on a tabstop\n" . $herecurr) && $fix) { - $fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/8)@e; + $fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/$tabsize)@e; } } } # check multi-line statement indentation matches previous line - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|(?:\*\s*)*$Lval\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) { $prevline =~ /^\+(\t*)(.*)$/; my $oldindent = $1; @@ -3048,8 +3362,8 @@ sub process { my $newindent = $2; my $goodtabindent = $oldindent . - "\t" x ($pos / 8) . - " " x ($pos % 8); + "\t" x ($pos / $tabsize) . + " " x ($pos % $tabsize); my $goodspaceindent = $oldindent . " " x $pos; if ($newindent ne $goodtabindent && @@ -3193,7 +3507,7 @@ sub process { # known declaration macros $sline =~ /^\+\s+$declaration_macros/ || # start of struct or union or enum - $sline =~ /^\+\s+(?:union|struct|enum|typedef)\b/ || + $sline =~ /^\+\s+(?:static\s+)?(?:const\s+)?(?:union|struct|enum|typedef)\b/ || # start or end of block or continuation of declaration $sline =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ || # bitfield continuation @@ -3273,18 +3587,6 @@ sub process { "CVS style keyword markers, these will _not_ be updated\n". $herecurr); } -# Blackfin: don't use __builtin_bfin_[cs]sync - if ($line =~ /__builtin_bfin_csync/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("CSYNC", - "use the CSYNC() macro in asm/blackfin.h\n" . $herevet); - } - if ($line =~ /__builtin_bfin_ssync/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("SSYNC", - "use the SSYNC() macro in asm/blackfin.h\n" . $herevet); - } - # check for old HOTPLUG __dev<foo> section markings if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) { WARN("HOTPLUG_SECTION", @@ -3532,11 +3834,11 @@ sub process { #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; if ($check && $s ne '' && - (($sindent % 8) != 0 || + (($sindent % $tabsize) != 0 || ($sindent < $indent) || ($sindent == $indent && ($s !~ /^\s*(?:\}|\{|else\b)/)) || - ($sindent > $indent + 8))) { + ($sindent > $indent + $tabsize))) { WARN("SUSPECT_CODE_INDENT", "suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); } @@ -3737,19 +4039,48 @@ sub process { "type '$tmp' should be specified in [[un]signed] [short|int|long|long long] order\n" . $herecurr); } +# check for unnecessary <signed> int declarations of short/long/long long + while ($sline =~ m{\b($TypeMisordered(\s*\*)*|$C90_int_types)\b}g) { + my $type = trim($1); + next if ($type !~ /\bint\b/); + next if ($type !~ /\b(?:short|long\s+long|long)\b/); + my $new_type = $type; + $new_type =~ s/\b\s*int\s*\b/ /; + $new_type =~ s/\b\s*(?:un)?signed\b\s*/ /; + $new_type =~ s/^const\s+//; + $new_type = "unsigned $new_type" if ($type =~ /\bunsigned\b/); + $new_type = "const $new_type" if ($type =~ /^const\b/); + $new_type =~ s/\s+/ /g; + $new_type = trim($new_type); + if (WARN("UNNECESSARY_INT", + "Prefer '$new_type' over '$type' as the int is unnecessary\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b\Q$type\E\b/$new_type/; + } + } + # check for static const char * arrays. if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) { WARN("STATIC_CONST_CHAR_ARRAY", "static const char * array should probably be static const char * const\n" . $herecurr); - } + } + +# check for initialized const char arrays that should be static const + if ($line =~ /^\+\s*const\s+(char|unsigned\s+char|_*u8|(?:[us]_)?int8_t)\s+\w+\s*\[\s*(?:\w+\s*)?\]\s*=\s*"/) { + if (WARN("STATIC_CONST_CHAR_ARRAY", + "const array should probably be static const\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(^.\s*)const\b/${1}static const/; + } + } # check for static char foo[] = "bar" declarations. if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) { WARN("STATIC_CONST_CHAR_ARRAY", "static char array declaration should probably be static const char\n" . $herecurr); - } + } # check for const <foo> const where <foo> is not a pointer or array type if ($sline =~ /\bconst\s+($BasicType)\s+const\b/) { @@ -3784,7 +4115,7 @@ sub process { } # check for function declarations without arguments like "int foo()" - if ($line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/) { + if ($line =~ /(\b$Type\s*$Ident)\s*\(\s*\)/) { if (ERROR("FUNCTION_WITHOUT_ARGS", "Bad function definition - $1() should probably be $1(void)\n" . $herecurr) && $fix) { @@ -3895,15 +4226,6 @@ sub process { "Prefer [subsystem eg: netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then pr_$level(... to printk(KERN_$orig ...\n" . $herecurr); } - if ($line =~ /\bpr_warning\s*\(/) { - if (WARN("PREFER_PR_LEVEL", - "Prefer pr_warn(... to pr_warning(...\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ - s/\bpr_warning\b/pr_warn/; - } - } - if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) { my $orig = $1; my $level = lc($orig); @@ -3921,9 +4243,20 @@ sub process { "ENOSYS means 'invalid syscall nr' and nothing else\n" . $herecurr); } +# ENOTSUPP is not a standard error code and should be avoided in new patches. +# Folks usually mean EOPNOTSUPP (also called ENOTSUP), when they type ENOTSUPP. +# Similarly to ENOSYS warning a small number of false positives is expected. + if (!$file && $line =~ /\bENOTSUPP\b/) { + if (WARN("ENOTSUPP", + "ENOTSUPP is not a SUSV4 error code, prefer EOPNOTSUPP\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bENOTSUPP\b/EOPNOTSUPP/; + } + } + # function brace can't be on same line, except for #defines of do while, # or if closed on same line - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $sline =~ /$Type\s*$Ident\s*$balanced_parens\s*\{/ && $sline !~ /\#\s*define\b.*do\s*\{/ && $sline !~ /}/) { @@ -4049,7 +4382,7 @@ sub process { my ($where, $prefix) = ($-[1], $1); if ($prefix !~ /$Type\s+$/ && ($where != 0 || $prefix !~ /^.\s+$/) && - $prefix !~ /[{,]\s+$/) { + $prefix !~ /[{,:]\s+$/) { if (ERROR("BRACKET_SPACE", "space prohibited before open square bracket '['\n" . $herecurr) && $fix) { @@ -4361,7 +4694,7 @@ sub process { ($op eq '>' && $ca =~ /<\S+\@\S+$/)) { - $ok = 1; + $ok = 1; } # for asm volatile statements @@ -4439,11 +4772,11 @@ sub process { #need space before brace following if, while, etc if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) || - $line =~ /do\{/) { + $line =~ /\b(?:else|do)\{/) { if (ERROR("SPACING", "space required before the open brace '{'\n" . $herecurr) && $fix) { - $fixed[$fixlinenr] =~ s/^(\+.*(?:do|\)))\{/$1 {/; + $fixed[$fixlinenr] =~ s/^(\+.*(?:do|else|\)))\{/$1 {/; } } @@ -4457,7 +4790,7 @@ sub process { # closing brace should have a space following it when it has anything # on the line - if ($line =~ /}(?!(?:,|;|\)))\S/) { + if ($line =~ /}(?!(?:,|;|\)|\}))\S/) { if (ERROR("SPACING", "space required after that close brace '}'\n" . $herecurr) && $fix) { @@ -4534,7 +4867,7 @@ sub process { # check for unnecessary parentheses around comparisons in if uses # when !drivers/staging or command-line uses --strict if (($realfile !~ m@^(?:drivers/staging/)@ || $check_orig) && - $^V && $^V ge 5.10.0 && defined($stat) && + $perl_version_ok && defined($stat) && $stat =~ /(^.\s*if\s*($balanced_parens))/) { my $if_stat = $1; my $test = substr($2, 1, -1); @@ -4571,7 +4904,7 @@ sub process { # return is not a function if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) { my $spacing = $1; - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/) { my $value = $1; $value = deparenthesize($value); @@ -4598,7 +4931,7 @@ sub process { } # if statements using unnecessary parentheses - ie: if ((foo == bar)) - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $line =~ /\bif\s*((?:\(\s*){2,})/) { my $openparens = $1; my $count = $openparens =~ tr@\(@\(@; @@ -4615,7 +4948,7 @@ sub process { # avoid cases like "foo + BAR < baz" # only fix matches surrounded by parentheses to avoid incorrect # conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5" - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) { my $lead = $1; my $const = $2; @@ -4696,7 +5029,7 @@ sub process { # conditional. substr($s, 0, length($c), ''); $s =~ s/\n.*//g; - $s =~ s/$;//g; # Remove any comments + $s =~ s/$;//g; # Remove any comments if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && $c !~ /}\s*while\s*/) { @@ -4735,7 +5068,7 @@ sub process { # if and else should not have general statements after it if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { my $s = $1; - $s =~ s/$;//g; # Remove any comments + $s =~ s/$;//g; # Remove any comments if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { ERROR("TRAILING_STATEMENTS", "trailing statements should be on next line\n" . $herecurr); @@ -4807,24 +5140,11 @@ sub process { while ($line =~ m{($Constant|$Lval)}g) { my $var = $1; -#gcc binary extension - if ($var =~ /^$Binary$/) { - if (WARN("GCC_BINARY_CONSTANT", - "Avoid gcc v4.3+ binary constant extension: <$var>\n" . $herecurr) && - $fix) { - my $hexval = sprintf("0x%x", oct($var)); - $fixed[$fixlinenr] =~ - s/\b$var\b/$hexval/; - } - } - #CamelCase if ($var !~ /^$Constant$/ && $var =~ /[A-Z][a-z]|[a-z][A-Z]/ && #Ignore Page<foo> variants $var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ && -#Ignore SI style variants like nS, mV and dB (ie: max_uV, regulator_min_uA_show) - $var !~ /^(?:[a-z_]*?)_?[a-z][A-Z](?:_[a-z_]+)?$/ && #ODP ignores $var !~ /\bCU_/ && $var !~ /\bPRI[diux]8/ && @@ -4835,6 +5155,9 @@ sub process { $var !~ /\bSCN[diux]16/ && $var !~ /\bSCN[diux]32/ && $var !~ /\bSCN[diux]64/ && +#Ignore SI style variants like nS, mV and dB +#(ie: max_uV, regulator_min_uA_show, RANGE_mA_VALUE) + $var !~ /^(?:[a-z0-9_]*|[A-Z0-9_]*)?_?[a-z][A-Z](?:_[a-z0-9_]+|_[A-Z0-9_]+)?$/ && #Ignore some three character SI units explicitly, like MiB and KHz $var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) { while ($var =~ m{($Ident)}g) { @@ -4915,6 +5238,7 @@ sub process { if (defined $define_args && $define_args ne "") { $define_args = substr($define_args, 1, length($define_args) - 2); $define_args =~ s/\s*//g; + $define_args =~ s/\\\+?//g; @def_args = split(",", $define_args); } @@ -4930,7 +5254,7 @@ sub process { { } - # Flatten any obvious string concatentation. + # Flatten any obvious string concatenation. while ($dstat =~ s/($String)\s*$Ident/$1/ || $dstat =~ s/$Ident\s*($String)/$1/) { @@ -4955,12 +5279,8 @@ sub process { #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; $ctx =~ s/\n*$//; - my $herectx = $here . "\n"; my $stmt_cnt = statement_rawlines($ctx); - - for (my $n = 0; $n < $stmt_cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } + my $herectx = get_stat_here($linenr, $stmt_cnt, $here); if ($dstat ne '' && $dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(), @@ -5012,10 +5332,10 @@ sub process { next if ($arg =~ /\.\.\./); next if ($arg =~ /^type$/i); my $tmp_stmt = $define_stmt; - $tmp_stmt =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g; + $tmp_stmt =~ s/\b(sizeof|typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g; $tmp_stmt =~ s/\#+\s*$arg\b//g; $tmp_stmt =~ s/\b$arg\s*\#\#//g; - my $use_cnt = $tmp_stmt =~ s/\b$arg\b//g; + my $use_cnt = () = $tmp_stmt =~ /\b$arg\b/g; if ($use_cnt > 1) { CHK("MACRO_ARG_REUSE", "Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx"); @@ -5032,12 +5352,9 @@ sub process { # check for macros with flow control, but without ## concatenation # ## concatenation is commonly a macro that defines a function so ignore those if ($has_flow_statement && !$has_arg_concat) { - my $herectx = $here . "\n"; my $cnt = statement_rawlines($ctx); + my $herectx = get_stat_here($linenr, $cnt, $here); - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } WARN("MACRO_WITH_FLOW_CONTROL", "Macros with flow control statements should be avoided\n" . "$herectx"); } @@ -5057,7 +5374,7 @@ sub process { # do {} while (0) macro tests: # single-statement macros do not need to be enclosed in do while (0) loop, # macro should not end with a semicolon - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $realfile !~ m@/vmlinux.lds.h$@ && $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) { my $ln = $linenr; @@ -5077,11 +5394,7 @@ sub process { $ctx =~ s/\n*$//; my $cnt = statement_rawlines($ctx); - my $herectx = $here . "\n"; - - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } + my $herectx = get_stat_here($linenr, $cnt, $here); if (($stmts =~ tr/;/;/) == 1 && $stmts !~ /^\s*(if|while|for|switch)\b/) { @@ -5095,27 +5408,13 @@ sub process { } elsif ($dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/) { $ctx =~ s/\n*$//; my $cnt = statement_rawlines($ctx); - my $herectx = $here . "\n"; - - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } + my $herectx = get_stat_here($linenr, $cnt, $here); WARN("TRAILING_SEMICOLON", "macros should not use a trailing semicolon\n" . "$herectx"); } } -# make sure symbols are always wrapped with VMLINUX_SYMBOL() ... -# all assignments may have only one of the following with an assignment: -# . -# ALIGN(...) -# VMLINUX_SYMBOL(...) - if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) { - WARN("MISSING_VMLINUX_SYMBOL", - "vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr); - } - # check for redundant bracing round if etc if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) { my ($level, $endln, @chunks) = @@ -5222,12 +5521,8 @@ sub process { } } if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) { - my $herectx = $here . "\n"; my $cnt = statement_rawlines($block); - - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } + my $herectx = get_stat_here($linenr, $cnt, $here); WARN("BRACES", "braces {} are not necessary for single statement blocks\n" . $herectx); @@ -5325,15 +5620,28 @@ sub process { } # concatenated string without spaces between elements - if ($line =~ /$String[A-Z_]/ || $line =~ /[A-Za-z0-9_]$String/) { - CHK("CONCATENATED_STRING", - "Concatenated strings should use spaces between elements\n" . $herecurr); + if ($line =~ /$String[A-Za-z0-9_]/ || $line =~ /[A-Za-z0-9_]$String/) { + if (CHK("CONCATENATED_STRING", + "Concatenated strings should use spaces between elements\n" . $herecurr) && + $fix) { + while ($line =~ /($String)/g) { + my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]); + $fixed[$fixlinenr] =~ s/\Q$extracted_string\E([A-Za-z0-9_])/$extracted_string $1/; + $fixed[$fixlinenr] =~ s/([A-Za-z0-9_])\Q$extracted_string\E/$1 $extracted_string/; + } + } } # uncoalesced string fragments if ($line =~ /$String\s*"/) { - WARN("STRING_FRAGMENTS", - "Consecutive strings are generally better as a single string\n" . $herecurr); + if (WARN("STRING_FRAGMENTS", + "Consecutive strings are generally better as a single string\n" . $herecurr) && + $fix) { + while ($line =~ /($String)(?=\s*")/g) { + my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]); + $fixed[$fixlinenr] =~ s/\Q$extracted_string\E\s*"/substr($extracted_string, 0, -1)/e; + } + } } # check for non-standard and hex prefixed decimal printf formats @@ -5369,9 +5677,14 @@ sub process { # warn about #if 0 if ($line =~ /^.\s*\#\s*if\s+0\b/) { - CHK("REDUNDANT_CODE", - "if this code is redundant consider removing it\n" . - $herecurr); + WARN("IF_0", + "Consider removing the code enclosed by this #if 0 and its #endif\n" . $herecurr); + } + +# warn about #if 1 + if ($line =~ /^.\s*\#\s*if\s+1\b/) { + WARN("IF_1", + "Consider removing the #if 1 and its #endif\n" . $herecurr); } # check for needless "if (<foo>) fn(<foo>)" uses @@ -5418,7 +5731,8 @@ sub process { my ($s, $c) = ctx_statement_block($linenr - 3, $realcnt, 0); # print("line: <$line>\nprevline: <$prevline>\ns: <$s>\nc: <$c>\n\n\n"); - if ($s =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*(?:devm_)?(?:[kv][czm]alloc(?:_node|_array)?\b|kstrdup|kmemdup|(?:dev_)?alloc_skb)/) { + if ($s =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*$allocFunctions\s*\(/ && + $s !~ /\b__GFP_NOWARN\b/ ) { WARN("OOM_MESSAGE", "Possible unnecessary 'out of memory' message\n" . $hereprev); } @@ -5442,7 +5756,7 @@ sub process { } # check for mask then right shift without a parentheses - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ && $4 !~ /^\&/) { # $LvalOrFunc may be &foo, ignore if so WARN("MASK_THEN_SHIFT", @@ -5450,7 +5764,7 @@ sub process { } # check for pointer comparisons to NULL - if ($^V && $^V ge 5.10.0) { + if ($perl_version_ok) { while ($line =~ /\b$LvalOrFunc\s*(==|\!=)\s*NULL\b/g) { my $val = $1; my $equal = "!"; @@ -5539,7 +5853,7 @@ sub process { # ignore udelay's < 10, however if (! ($delay < 10) ) { CHK("USLEEP_RANGE", - "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $herecurr); + "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst\n" . $herecurr); } if ($delay > 2000) { WARN("LONG_UDELAY", @@ -5551,7 +5865,7 @@ sub process { if ($line =~ /\bmsleep\s*\((\d+)\);/) { if ($1 < 20) { WARN("MSLEEP", - "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $herecurr); + "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.rst\n" . $herecurr); } } @@ -5700,6 +6014,18 @@ sub process { "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr); } +# Check for __attribute__ section, prefer __section + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(.*_*section_*\s*\(\s*("[^"]*")/) { + my $old = substr($rawline, $-[1], $+[1] - $-[1]); + my $new = substr($old, 1, -1); + if (WARN("PREFER_SECTION", + "__section($new) is preferred over __attribute__((section($old)))\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*_*section_*\s*\(\s*\Q$old\E\s*\)\s*\)\s*\)/__section($new)/; + } + } + # Check for __attribute__ format(printf, prefer __printf if ($realfile !~ m@\binclude/uapi/@ && $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) { @@ -5722,7 +6048,7 @@ sub process { } # Check for __attribute__ weak, or __weak declarations (may have link issues) - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $line =~ /(?:$Declare|$DeclareMisordered)\s*$Ident\s*$balanced_parens\s*(?:$Attribute)?\s*;/ && ($line =~ /\b__attribute__\s*\(\s*\(.*\bweak\b/ || $line =~ /\b__weak\b/)) { @@ -5803,41 +6129,58 @@ sub process { } } - # check for vsprintf extension %p<foo> misuses - if ($^V && $^V ge 5.10.0 && +# check for vsprintf extension %p<foo> misuses + if ($perl_version_ok && defined $stat && $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s && $1 !~ /^_*volatile_*$/) { - my $bad_extension = ""; + my $stat_real; + my $lc = $stat =~ tr@\n@@; $lc = $lc + $linenr; for (my $count = $linenr; $count <= $lc; $count++) { + my $specifier; + my $extension; + my $qualifier; + my $bad_specifier = ""; my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); $fmt =~ s/%%//g; - if ($fmt =~ /(\%[\*\d\.]*p(?![\WSsBKRraEhMmIiUDdgVCbGNOx]).)/) { - $bad_extension = $1; - last; - } - } - if ($bad_extension ne "") { - my $stat_real = raw_line($linenr, 0); - my $ext_type = "Invalid"; - my $use = ""; - for (my $count = $linenr + 1; $count <= $lc; $count++) { - $stat_real = $stat_real . "\n" . raw_line($count, 0); + + while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) { + $specifier = $1; + $extension = $2; + $qualifier = $3; + if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxtf]/ || + ($extension eq "f" && + defined $qualifier && $qualifier !~ /^w/)) { + $bad_specifier = $specifier; + last; + } + if ($extension eq "x" && !defined($stat_real)) { + if (!defined($stat_real)) { + $stat_real = get_stat_real($linenr, $lc); + } + WARN("VSPRINTF_SPECIFIER_PX", + "Using vsprintf specifier '\%px' potentially exposes the kernel memory layout, if you don't really need the address please consider using '\%p'.\n" . "$here\n$stat_real\n"); + } } - if ($bad_extension =~ /p[Ff]/) { - $ext_type = "Deprecated"; - $use = " - use %pS instead"; - $use =~ s/pS/ps/ if ($bad_extension =~ /pf/); + if ($bad_specifier ne "") { + my $stat_real = get_stat_real($linenr, $lc); + my $ext_type = "Invalid"; + my $use = ""; + if ($bad_specifier =~ /p[Ff]/) { + $use = " - use %pS instead"; + $use =~ s/pS/ps/ if ($bad_specifier =~ /pf/); + } + + WARN("VSPRINTF_POINTER_EXTENSION", + "$ext_type vsprintf pointer extension '$bad_specifier'$use\n" . "$here\n$stat_real\n"); } - WARN("VSPRINTF_POINTER_EXTENSION", - "$ext_type vsprintf pointer extension '$bad_extension'$use\n" . "$here\n$stat_real\n"); } } # Check for misused memsets - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/) { @@ -5855,7 +6198,7 @@ sub process { } # Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar) -# if ($^V && $^V ge 5.10.0 && +# if ($perl_version_ok && # defined $stat && # $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { # if (WARN("PREFER_ETHER_ADDR_COPY", @@ -5866,7 +6209,7 @@ sub process { # } # Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar) -# if ($^V && $^V ge 5.10.0 && +# if ($perl_version_ok && # defined $stat && # $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { # WARN("PREFER_ETHER_ADDR_EQUAL", @@ -5875,7 +6218,7 @@ sub process { # check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr # check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr -# if ($^V && $^V ge 5.10.0 && +# if ($perl_version_ok && # defined $stat && # $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { # @@ -5897,7 +6240,7 @@ sub process { # } # typecasts on min/max could be min_t/max_t - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) { if (defined $2 || defined $7) { @@ -5921,23 +6264,23 @@ sub process { } # check usleep_range arguments - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) { my $min = $1; my $max = $7; if ($min eq $max) { WARN("USLEEP_RANGE", - "usleep_range should not use min == max args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n"); + "usleep_range should not use min == max args; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n"); } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ && $min > $max) { WARN("USLEEP_RANGE", - "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n"); + "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n"); } } # check for naked sscanf - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $line =~ /\bsscanf\b/ && ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ && @@ -5945,24 +6288,18 @@ sub process { $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) { my $lc = $stat =~ tr@\n@@; $lc = $lc + $linenr; - my $stat_real = raw_line($linenr, 0); - for (my $count = $linenr + 1; $count <= $lc; $count++) { - $stat_real = $stat_real . "\n" . raw_line($count, 0); - } + my $stat_real = get_stat_real($linenr, $lc); WARN("NAKED_SSCANF", "unchecked sscanf return value\n" . "$here\n$stat_real\n"); } # check for simple sscanf that should be kstrto<foo> - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $line =~ /\bsscanf\b/) { my $lc = $stat =~ tr@\n@@; $lc = $lc + $linenr; - my $stat_real = raw_line($linenr, 0); - for (my $count = $linenr + 1; $count <= $lc; $count++) { - $stat_real = $stat_real . "\n" . raw_line($count, 0); - } + my $stat_real = get_stat_real($linenr, $lc); if ($stat_real =~ /\bsscanf\b\s*\(\s*$FuncArg\s*,\s*("[^"]+")/) { my $format = $6; my $count = $format =~ tr@%@%@; @@ -6015,13 +6352,17 @@ sub process { } # check for function declarations that have arguments without identifier names +# while avoiding uninitialized_var(x) if (defined $stat && - $stat =~ /^.\s*(?:extern\s+)?$Type\s*(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*\(\s*([^{]+)\s*\)\s*;/s && - $1 ne "void") { - my $args = trim($1); + $stat =~ /^.\s*(?:extern\s+)?$Type\s*(?:($Ident)|\(\s*\*\s*$Ident\s*\))\s*\(\s*([^{]+)\s*\)\s*;/s && + (!defined($1) || + (defined($1) && $1 ne "uninitialized_var")) && + $2 ne "void") { + my $args = trim($2); while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) { my $arg = trim($1); - if ($arg =~ /^$Type$/ && $arg !~ /enum\s+$Ident$/) { + if ($arg =~ /^$Type$/ && + $arg !~ /enum\s+$Ident$/) { WARN("FUNCTION_ARGUMENTS", "function definition argument '$arg' should also have an identifier name\n" . $herecurr); } @@ -6029,7 +6370,7 @@ sub process { } # check for function definitions - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^.\s*(?:$Storage\s+)?$Type\s*($Ident)\s*$balanced_parens\s*{/s) { $context_function = $1; @@ -6061,22 +6402,22 @@ sub process { } } -# check for pointless casting of kmalloc return - if ($line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/) { +# check for pointless casting of alloc functions + if ($line =~ /\*\s*\)\s*$allocFunctions\b/) { WARN("UNNECESSARY_CASTS", "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); } # alloc style # p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...) - if ($^V && $^V ge 5.10.0 && - $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*([kv][mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) { + if ($perl_version_ok && + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k|v)[mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) { CHK("ALLOC_SIZEOF_STRUCT", "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr); } # check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) { my $oldfunc = $3; @@ -6092,12 +6433,9 @@ sub process { } if ($r1 !~ /^sizeof\b/ && $r2 =~ /^sizeof\s*\S/ && !($r1 =~ /^$Constant$/ || $r1 =~ /^[A-Z_][A-Z0-9_]*$/)) { - my $ctx = ''; - my $herectx = $here . "\n"; my $cnt = statement_rawlines($stat); - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } + my $herectx = get_stat_here($linenr, $cnt, $here); + if (WARN("ALLOC_WITH_MULTIPLY", "Prefer $newfunc over $oldfunc with multiply\n" . $herectx) && $cnt == 1 && @@ -6108,8 +6446,9 @@ sub process { } # check for krealloc arg reuse - if ($^V && $^V ge 5.10.0 && - $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*\1\s*,/) { + if ($perl_version_ok && + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*($Lval)\s*,/ && + $1 eq $3) { WARN("KREALLOC_ARG_REUSE", "Reusing the krealloc arg is almost always a bug\n" . $herecurr); } @@ -6176,16 +6515,35 @@ sub process { } } +# check for /* fallthrough */ like comment, prefer fallthrough; + my @fallthroughs = ( + 'fallthrough', + '@fallthrough@', + 'lint -fallthrough[ \t]*', + 'intentional(?:ly)?[ \t]*fall(?:(?:s | |-)[Tt]|t)hr(?:ough|u|ew)', + '(?:else,?\s*)?FALL(?:S | |-)?THR(?:OUGH|U|EW)[ \t.!]*(?:-[^\n\r]*)?', + 'Fall(?:(?:s | |-)[Tt]|t)hr(?:ough|u|ew)[ \t.!]*(?:-[^\n\r]*)?', + 'fall(?:s | |-)?thr(?:ough|u|ew)[ \t.!]*(?:-[^\n\r]*)?', + ); + if ($raw_comment ne '') { + foreach my $ft (@fallthroughs) { + if ($raw_comment =~ /$ft/) { + my $msg_level = \&WARN; + $msg_level = \&CHK if ($file); + &{$msg_level}("PREFER_FALLTHROUGH", + "Prefer 'fallthrough;' over fallthrough comment\n" . $herecurr); + last; + } + } + } + # check for switch/default statements without a break; - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) { - my $ctx = ''; - my $herectx = $here . "\n"; my $cnt = statement_rawlines($stat); - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } + my $herectx = get_stat_here($linenr, $cnt, $here); + WARN("DEFAULT_NO_BREAK", "switch default: should use break\n" . $herectx); } @@ -6256,6 +6614,20 @@ sub process { "please use device_initcall() or more appropriate function instead of __initcall() (see include/linux/init.h)\n" . $herecurr); } +# check for spin_is_locked(), suggest lockdep instead + if ($line =~ /\bspin_is_locked\(/) { + WARN("USE_LOCKDEP", + "Where possible, use lockdep_assert_held instead of assertions based on spin_is_locked\n" . $herecurr); + } + +# check for deprecated apis + if ($line =~ /\b($deprecated_apis_search)\b\s*\(/) { + my $deprecated_api = $1; + my $new_api = $deprecated_apis{$deprecated_api}; + WARN("DEPRECATED_API", + "Deprecated use of '$deprecated_api', prefer '$new_api' instead\n" . $herecurr); + } + # check for various structs that are normally const (ops, kgdb, device_tree) # and avoid what seem like struct definitions 'struct foo {' if ($line !~ /\bconst\b/ && @@ -6284,12 +6656,18 @@ sub process { } # likely/unlikely comparisons similar to "(likely(foo) > 0)" - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) { WARN("LIKELY_MISUSE", "Using $1 should generally have parentheses around the comparison\n" . $herecurr); } +# nested likely/unlikely calls + if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) { + WARN("LIKELY_MISUSE", + "nested (un)?likely() calls, $1 already uses unlikely() internally\n" . $herecurr); + } + # whine mightly about in_atomic if ($line =~ /\bin_atomic\s*\(/) { if ($realfile =~ m@^drivers/@) { @@ -6327,7 +6705,7 @@ sub process { # check for DEVICE_ATTR uses that could be DEVICE_ATTR_<FOO> # and whether or not function naming is typical and if # DEVICE_ATTR permissions uses are unusual too - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /\bDEVICE_ATTR\s*\(\s*(\w+)\s*,\s*\(?\s*(\s*(?:${multi_mode_perms_string_search}|0[0-7]{3,3})\s*)\s*\)?\s*,\s*(\w+)\s*,\s*(\w+)\s*\)/) { my $var = $1; @@ -6387,7 +6765,7 @@ sub process { # specific definition of not visible in sysfs. # o Ignore proc_create*(...) uses with a decimal 0 permission as that means # use the default permissions - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $line =~ /$mode_perms_search/) { foreach my $entry (@mode_permission_funcs) { @@ -6396,10 +6774,7 @@ sub process { my $lc = $stat =~ tr@\n@@; $lc = $lc + $linenr; - my $stat_real = raw_line($linenr, 0); - for (my $count = $linenr + 1; $count <= $lc; $count++) { - $stat_real = $stat_real . "\n" . raw_line($count, 0); - } + my $stat_real = get_stat_real($linenr, $lc); my $skip_args = ""; if ($arg_pos > 1) { @@ -6425,7 +6800,7 @@ sub process { } # check for uses of S_<PERMS> that could be octal for readability - if ($line =~ /\b($multi_mode_perms_string_search)\b/) { + while ($line =~ m{\b($multi_mode_perms_string_search)\b}g) { my $oval = $1; my $octal = perms_to_octal($oval); if (WARN("SYMBOLIC_PERMS", @@ -6452,6 +6827,12 @@ sub process { "unknown module license " . $extracted_string . "\n" . $herecurr); } } + +# check for sysctl duplicate constants + if ($line =~ /\.extra[12]\s*=\s*&(zero|one|int_max)\b/) { + WARN("DUPLICATED_SYSCTL_CONST", + "duplicated sysctl range checking value '$1', consider using the shared one in include/linux/sysctl.h\n" . $herecurr); + } } # If we have no input at all, then there is nothing to report on @@ -6476,9 +6857,14 @@ sub process { ERROR("NOT_UNIFIED_DIFF", "Does not appear to be a unified-diff format patch\n"); } - if ($is_patch && $has_commit_log && $chk_signoff && $signoff == 0) { - ERROR("MISSING_SIGN_OFF", - "Missing Signed-off-by: line(s)\n"); + if ($is_patch && $has_commit_log && $chk_signoff) { + if ($signoff == 0) { + ERROR("MISSING_SIGN_OFF", + "Missing Signed-off-by: line(s)\n"); + } elsif (!$authorsignoff) { + WARN("NO_AUTHOR_SIGN_OFF", + "Missing Signed-off-by: line by nominal patch author '$author'\n"); + } } print report_dump(); @@ -6558,4 +6944,4 @@ EOM } } return $clean; -} +}
\ No newline at end of file diff --git a/test/Makefile.inc b/test/Makefile.inc index aa3881519..d3af8dcff 100644 --- a/test/Makefile.inc +++ b/test/Makefile.inc @@ -4,7 +4,7 @@ include $(top_srcdir)/Makefile.inc COMMON_DIR = $(top_builddir)/test/common -LIBODP = $(LIB)/libodphelper.la $(LIB)/libodp-linux.la +LIBODP = $(LIB)/libodphelper.la $(LIB)/lib$(ODP_LIB_NAME).la LIBCUNIT_COMMON = $(COMMON_DIR)/libcunit_common.la LIBCPUMASK_COMMON = $(COMMON_DIR)/libcpumask_common.la diff --git a/test/common/odp_cunit_common.h b/test/common/odp_cunit_common.h index e8f14daa6..55e52ce1c 100644 --- a/test/common/odp_cunit_common.h +++ b/test/common/odp_cunit_common.h @@ -15,6 +15,7 @@ #include <stdint.h> #include <inttypes.h> +#include <stdlib.h> #include <CUnit/Basic.h> #include <odp_api.h> @@ -105,4 +106,26 @@ void odp_cunit_register_global_term(int (*func_term_ptr)(odp_instance_t inst)); int odp_cunit_ret(int val); int odp_cunit_print_inactive(void); +/* + * Wrapper for CU_ASSERT_FATAL implementation to show the compiler that + * the function does not return if the assertion fails. This reduces bogus + * warnings generated from the code after the fatal assert. + */ +static inline void odp_cu_assert_fatal(CU_BOOL value, unsigned int line, + const char *condition, const char *file) +{ + CU_assertImplementation(value, line, condition, file, "", CU_TRUE); + + if (!value) { + /* not reached */ + abort(); /* this has noreturn function attribute */ + for (;;) /* this also shows that return is not possible */ + ; + } +} + +#undef CU_ASSERT_FATAL +#define CU_ASSERT_FATAL(value) \ + { odp_cu_assert_fatal((value), __LINE__, #value, __FILE__); } + #endif /* ODP_CUNICT_COMMON_H */ diff --git a/test/performance/odp_bench_packet.c b/test/performance/odp_bench_packet.c index d139006b3..c6798556e 100644 --- a/test/performance/odp_bench_packet.c +++ b/test/performance/odp_bench_packet.c @@ -126,7 +126,7 @@ typedef struct { /** Number of benchmark functions */ int num_bench; /** Break worker loop if set to 1 */ - int exit_thread; + odp_atomic_u32_t exit_thread; struct { /** Test packet length */ uint32_t len; @@ -168,7 +168,7 @@ static void sig_handler(int signo ODP_UNUSED) { if (gbl_args == NULL) return; - gbl_args->exit_thread = 1; + odp_atomic_store_u32(&gbl_args->exit_thread, 1); } /** @@ -183,7 +183,7 @@ static void run_indef(args_t *args, int idx) printf("Running %s() indefinitely\n", desc); - while (!gbl_args->exit_thread) { + while (!odp_atomic_load_u32(&gbl_args->exit_thread)) { int ret; if (args->bench[idx].init != NULL) @@ -1789,6 +1789,7 @@ int main(int argc, char *argv[]) } memset(gbl_args, 0, sizeof(args_t)); + odp_atomic_init_u32(&gbl_args->exit_thread, 0); gbl_args->bench = test_suite; gbl_args->num_bench = sizeof(test_suite) / sizeof(test_suite[0]); diff --git a/test/performance/odp_cpu_bench.c b/test/performance/odp_cpu_bench.c index 38c18513a..a4999ae27 100644 --- a/test/performance/odp_cpu_bench.c +++ b/test/performance/odp_cpu_bench.c @@ -92,7 +92,7 @@ typedef struct { /* Test lookup table */ lookup_entry_t *lookup_tbl; /* Break workers loop if set to 1 */ - int exit_threads; + odp_atomic_u32_t exit_threads; } args_t; /* Global pointer to args */ @@ -175,7 +175,7 @@ static void sig_handler(int signo ODP_UNUSED) { if (gbl_args == NULL) return; - gbl_args->exit_threads = 1; + odp_atomic_store_u32(&gbl_args->exit_threads, 1); } static inline void init_packet(odp_packet_t pkt, uint32_t seq, uint16_t group) @@ -278,7 +278,7 @@ static int run_thread(void *arg) c1 = odp_cpu_cycles(); t1 = odp_time_local(); - while (!gbl_args->exit_threads) { + while (!odp_atomic_load_u32(&gbl_args->exit_threads)) { odp_event_t event_tbl[MAX_EVENT_BURST]; odp_queue_t dst_queue; int num_events; @@ -469,10 +469,10 @@ static int print_stats(int num_workers, stats_t **thr_stats, int duration, pkts_prev = pkts; elapsed += accuracy; - } while (!gbl_args->exit_threads && + } while (!odp_atomic_load_u32(&gbl_args->exit_threads) && (loop_forever || (elapsed < duration))); - gbl_args->exit_threads = 1; + odp_atomic_store_u32(&gbl_args->exit_threads, 1); odp_barrier_wait(&gbl_args->term_barrier); pkts = 0; @@ -511,6 +511,7 @@ static int print_stats(int num_workers, stats_t **thr_stats, int duration, static void gbl_args_init(args_t *args) { memset(args, 0, sizeof(args_t)); + odp_atomic_init_u32(&args->exit_threads, 0); } /** diff --git a/test/performance/odp_l2fwd.c b/test/performance/odp_l2fwd.c index d899aa743..267e74950 100644 --- a/test/performance/odp_l2fwd.c +++ b/test/performance/odp_l2fwd.c @@ -174,7 +174,7 @@ typedef struct { * mode. */ uint8_t dst_port_from_idx[MAX_PKTIO_INDEXES]; /* Break workers loop if set to 1 */ - int exit_threads; + odp_atomic_u32_t exit_threads; } args_t; @@ -185,7 +185,7 @@ static void sig_handler(int signo ODP_UNUSED) { if (gbl_args == NULL) return; - gbl_args->exit_threads = 1; + odp_atomic_store_u32(&gbl_args->exit_threads, 1); } /* @@ -367,7 +367,7 @@ static int run_worker_sched_mode(void *arg) odp_barrier_wait(&gbl_args->init_barrier); /* Loop packets */ - while (!gbl_args->exit_threads) { + while (!odp_atomic_load_u32(&gbl_args->exit_threads)) { odp_event_t ev_tbl[MAX_PKT_BURST]; odp_packet_t pkt_tbl[MAX_PKT_BURST]; int sent; @@ -492,7 +492,7 @@ static int run_worker_plain_queue_mode(void *arg) odp_barrier_wait(&gbl_args->init_barrier); /* Loop packets */ - while (!gbl_args->exit_threads) { + while (!odp_atomic_load_u32(&gbl_args->exit_threads)) { int sent; unsigned tx_drops; odp_event_t event[MAX_PKT_BURST]; @@ -627,7 +627,7 @@ static int run_worker_direct_mode(void *arg) odp_barrier_wait(&gbl_args->init_barrier); /* Loop packets */ - while (!gbl_args->exit_threads) { + while (!odp_atomic_load_u32(&gbl_args->exit_threads)) { int sent; unsigned tx_drops; @@ -927,7 +927,7 @@ static int print_speed_stats(int num_workers, stats_t **thr_stats, pkts_prev = pkts; } elapsed += timeout; - } while (!gbl_args->exit_threads && (loop_forever || + } while (!odp_atomic_load_u32(&gbl_args->exit_threads) && (loop_forever || (elapsed < duration))); if (stats_enabled) @@ -1503,6 +1503,7 @@ static void gbl_args_init(args_t *args) int pktio, queue; memset(args, 0, sizeof(args_t)); + odp_atomic_init_u32(&args->exit_threads, 0); for (pktio = 0; pktio < MAX_PKTIOS; pktio++) { args->pktios[pktio].pktio = ODP_PKTIO_INVALID; @@ -1852,7 +1853,7 @@ int main(int argc, char *argv[]) } } - gbl_args->exit_threads = 1; + odp_atomic_store_u32(&gbl_args->exit_threads, 1); if (gbl_args->appl.in_mode != DIRECT_RECV) odp_barrier_wait(&gbl_args->term_barrier); diff --git a/test/performance/odp_packet_gen.c b/test/performance/odp_packet_gen.c index eaca511e6..3287e7a9a 100644 --- a/test/performance/odp_packet_gen.c +++ b/test/performance/odp_packet_gen.c @@ -4,6 +4,11 @@ * SPDX-License-Identifier: BSD-3-Clause */ +/* enable usleep */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #include <stdio.h> #include <string.h> #include <stdint.h> @@ -11,6 +16,7 @@ #include <signal.h> #include <stdlib.h> #include <getopt.h> +#include <unistd.h> #include <odp_api.h> #include <odp/helper/odph_api.h> @@ -27,6 +33,7 @@ typedef struct test_options_t { uint64_t gap_nsec; uint64_t quit; + uint64_t update_msec; uint32_t num_rx; uint32_t num_tx; uint32_t num_cpu; @@ -79,6 +86,12 @@ typedef struct ODP_ALIGNED_CACHE thread_stat_t { int thread_type; + struct { + uint64_t rx_packets; + uint64_t tx_packets; + + } pktio[MAX_PKTIOS]; + } thread_stat_t; typedef struct test_global_t { @@ -118,36 +131,38 @@ static void print_usage(void) " At least one interface is required.\n" "\n" " Optional:\n" - " -e, --eth_dst <mac> Destination MAC address. Comma-separated list of\n" - " addresses (no spaces), one address per packet IO\n" - " interface e.g. AA:BB:CC:DD:EE:FF,11:22:33:44:55:66\n" - " Default per interface: 02:00:00:A0:B0:CX, where X = 0,1,...\n" - " -v, --vlan <tpid:tci> VLAN configuration. Comma-separated list of VLAN TPID:TCI\n" - " values in hexadecimal, starting from the outer most VLAN.\n" - " For example:\n" - " VLAN 200 (decimal): 8100:c8\n" - " Double tagged VLANs 1 and 2: 88a8:1,8100:2\n" - " -r, --num_rx Number of receive threads. Default: 1\n" - " -t, --num_tx Number of transmit threads. Default: 1\n" - " -n, --num_pkt Number of packets in the pool. Default: 1000\n" - " -l, --len Packet length. Default: 512\n" - " -b, --burst_size Transmit burst size. Default: 8\n" - " -x, --bursts Number of bursts per one transmit round. Default: 1\n" - " -g, --gap Gap between transmit rounds in nsec. Default: 1000000\n" - " Transmit packet rate per interface:\n" - " num_tx * burst_size * bursts * (10^9 / gap)\n" - " -s, --ipv4_src IPv4 source address. Default: 192.168.0.1\n" - " -d, --ipv4_dst IPv4 destination address. Default: 192.168.0.2\n" - " -o, --udp_src UDP source port. Default: 10000\n" - " -p, --udp_dst UDP destination port. Default: 20000\n" - " -c, --c_mode <counts> Counter mode for incrementing UDP port numbers.\n" - " Specify the number of port numbers used starting from\n" - " udp_src/udp_dst. Comma-serarated (no spaces) list of\n" - " count values: <udp_src count>,<udp_dst count>\n" - " Default value: 0,0\n" - " -q, --quit Quit after this many transmit rounds.\n" - " Default: 0 (don't quit)\n" - " -h, --help This help\n" + " -e, --eth_dst <mac> Destination MAC address. Comma-separated list of\n" + " addresses (no spaces), one address per packet IO\n" + " interface e.g. AA:BB:CC:DD:EE:FF,11:22:33:44:55:66\n" + " Default per interface: 02:00:00:A0:B0:CX, where X = 0,1,...\n" + " -v, --vlan <tpid:tci> VLAN configuration. Comma-separated list of VLAN TPID:TCI\n" + " values in hexadecimal, starting from the outer most VLAN.\n" + " For example:\n" + " VLAN 200 (decimal): 8100:c8\n" + " Double tagged VLANs 1 and 2: 88a8:1,8100:2\n" + " -r, --num_rx Number of receive threads. Default: 1\n" + " -t, --num_tx Number of transmit threads. Default: 1\n" + " -n, --num_pkt Number of packets in the pool. Default: 1000\n" + " -l, --len Packet length. Default: 512\n" + " -b, --burst_size Transmit burst size. Default: 8\n" + " -x, --bursts Number of bursts per one transmit round. Default: 1\n" + " -g, --gap Gap between transmit rounds in nsec. Default: 1000000\n" + " Transmit packet rate per interface:\n" + " num_tx * burst_size * bursts * (10^9 / gap)\n" + " -s, --ipv4_src IPv4 source address. Default: 192.168.0.1\n" + " -d, --ipv4_dst IPv4 destination address. Default: 192.168.0.2\n" + " -o, --udp_src UDP source port. Default: 10000\n" + " -p, --udp_dst UDP destination port. Default: 20000\n" + " -c, --c_mode <counts> Counter mode for incrementing UDP port numbers.\n" + " Specify the number of port numbers used starting from\n" + " udp_src/udp_dst. Comma-serarated (no spaces) list of\n" + " count values: <udp_src count>,<udp_dst count>\n" + " Default value: 0,0\n" + " -q, --quit Quit after this many transmit rounds.\n" + " Default: 0 (don't quit)\n" + " -u, --update_stat <msec> Update and print statistics every <msec> milliseconds.\n" + " 0: Don't print statistics periodically (default)\n" + " -h, --help This help\n" "\n"); } @@ -202,27 +217,28 @@ static int parse_options(int argc, char *argv[], test_global_t *global) uint8_t default_eth_dst[6] = {0x02, 0x00, 0x00, 0xa0, 0xb0, 0xc0}; static const struct option longopts[] = { - {"interface", required_argument, NULL, 'i'}, - {"eth_dst", required_argument, NULL, 'e'}, - {"num_rx", required_argument, NULL, 'r'}, - {"num_tx", required_argument, NULL, 't'}, - {"num_pkt", required_argument, NULL, 'n'}, - {"len", required_argument, NULL, 'l'}, - {"burst_size", required_argument, NULL, 'b'}, - {"bursts", required_argument, NULL, 'x'}, - {"gap", required_argument, NULL, 'g'}, - {"vlan", required_argument, NULL, 'v'}, - {"ipv4_src", required_argument, NULL, 's'}, - {"ipv4_dst", required_argument, NULL, 'd'}, - {"udp_src", required_argument, NULL, 'o'}, - {"udp_dst", required_argument, NULL, 'p'}, - {"c_mode", required_argument, NULL, 'c'}, - {"quit", required_argument, NULL, 'q'}, - {"help", no_argument, NULL, 'h'}, + {"interface", required_argument, NULL, 'i'}, + {"eth_dst", required_argument, NULL, 'e'}, + {"num_rx", required_argument, NULL, 'r'}, + {"num_tx", required_argument, NULL, 't'}, + {"num_pkt", required_argument, NULL, 'n'}, + {"len", required_argument, NULL, 'l'}, + {"burst_size", required_argument, NULL, 'b'}, + {"bursts", required_argument, NULL, 'x'}, + {"gap", required_argument, NULL, 'g'}, + {"vlan", required_argument, NULL, 'v'}, + {"ipv4_src", required_argument, NULL, 's'}, + {"ipv4_dst", required_argument, NULL, 'd'}, + {"udp_src", required_argument, NULL, 'o'}, + {"udp_dst", required_argument, NULL, 'p'}, + {"c_mode", required_argument, NULL, 'c'}, + {"quit", required_argument, NULL, 'q'}, + {"update_stat", required_argument, NULL, 'u'}, + {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; - static const char *shortopts = "+i:e:r:t:n:l:b:x:g:v:s:d:o:p:c:q:h"; + static const char *shortopts = "+i:e:r:t:n:l:b:x:g:v:s:d:o:p:c:q:u:h"; test_options->num_pktio = 0; test_options->num_rx = 1; @@ -244,6 +260,7 @@ static int parse_options(int argc, char *argv[], test_global_t *global) test_options->c_mode.udp_src = 0; test_options->c_mode.udp_dst = 0; test_options->quit = 0; + test_options->update_msec = 0; for (i = 0; i < MAX_PKTIOS; i++) { memcpy(global->pktio[i].eth_dst.addr, default_eth_dst, 6); @@ -375,6 +392,9 @@ static int parse_options(int argc, char *argv[], test_global_t *global) case 'q': test_options->quit = atoll(optarg); break; + case 'u': + test_options->update_msec = atoll(optarg); + break; case 'h': /* fall through */ default: @@ -764,9 +784,12 @@ static int rx_thread(void *arg) { int i, thr, num; uint32_t exit_test; + uint64_t bytes; odp_time_t t1, t2; + odp_packet_t pkt; thread_arg_t *thread_arg = arg; test_global_t *global = thread_arg->global; + int periodic_stat = global->test_options.update_msec ? 1 : 0; uint64_t rx_timeouts = 0; uint64_t rx_packets = 0; uint64_t rx_bytes = 0; @@ -808,15 +831,24 @@ static int rx_thread(void *arg) clock_started = 1; } + bytes = 0; for (i = 0; i < num; i++) { - odp_packet_t pkt; - pkt = odp_packet_from_event(ev[i]); - rx_bytes += odp_packet_len(pkt); + bytes += odp_packet_len(pkt); } - odp_event_free_multi(ev, num); rx_packets += num; + rx_bytes += bytes; + + if (odp_unlikely(periodic_stat)) { + /* All packets from the same queue are from the same pktio interface */ + int index = odp_packet_input_index(odp_packet_from_event(ev[0])); + + if (index >= 0) + global->stat[thr].pktio[index].rx_packets += num; + } + + odp_event_free_multi(ev, num); } t2 = odp_time_local(); @@ -864,6 +896,9 @@ static int init_packets(test_global_t *global, int pktio, uint32_t udp_src_cnt = 0; uint32_t udp_dst_cnt = 0; + if (num_vlan > MAX_VLANS) + num_vlan = MAX_VLANS; + for (i = 0; i < num; i++) { pkt = packet[i]; pkt_len = odp_packet_len(pkt); @@ -1003,6 +1038,7 @@ static int tx_thread(void *arg) thread_arg_t *thread_arg = arg; test_global_t *global = thread_arg->global; test_options_t *test_options = &global->test_options; + int periodic_stat = test_options->update_msec ? 1 : 0; odp_pool_t pool = global->pool; uint64_t gap_nsec = test_options->gap_nsec; uint64_t quit = test_options->quit; @@ -1087,6 +1123,10 @@ static int tx_thread(void *arg) tx_packets += sent; if (odp_unlikely(sent < burst_size)) tx_drops += burst_size - sent; + + if (odp_unlikely(periodic_stat)) + global->stat[thr].pktio[i].tx_packets += sent; + } } } @@ -1161,7 +1201,65 @@ static int start_workers(test_global_t *global, odp_instance_t instance) return 0; } -static int print_stat(test_global_t *global) +static void print_periodic_stat(test_global_t *global, uint64_t nsec) +{ + int i, j; + int num_pktio = global->test_options.num_pktio; + double sec = nsec / 1000000000.0; + uint64_t num_tx[num_pktio]; + uint64_t num_rx[num_pktio]; + + for (i = 0; i < num_pktio; i++) { + num_tx[i] = 0; + num_rx[i] = 0; + + for (j = 0; j < ODP_THREAD_COUNT_MAX; j++) { + if (global->stat[j].thread_type == RX_THREAD) + num_rx[i] += global->stat[j].pktio[i].rx_packets; + else if (global->stat[j].thread_type == TX_THREAD) + num_tx[i] += global->stat[j].pktio[i].tx_packets; + } + } + + printf(" TX: %12.6fs", sec); + for (i = 0; i < num_pktio; i++) + printf(" %10" PRIu64 "", num_tx[i]); + + printf("\n RX: %12.6fs", sec); + for (i = 0; i < num_pktio; i++) + printf(" %10" PRIu64 "", num_rx[i]); + + printf("\n"); +} + +static void periodic_print_loop(test_global_t *global) +{ + odp_time_t t1, t2; + uint64_t nsec; + int i; + int num_pktio = global->test_options.num_pktio; + + printf("\n\nPackets per interface\n"); + printf(" Dir Time"); + for (i = 0; i < num_pktio; i++) + printf(" %10i", i); + + printf("\n -----------------"); + for (i = 0; i < num_pktio; i++) + printf("-----------"); + + printf("\n"); + + t1 = odp_time_local(); + while (odp_atomic_load_u32(&global->exit_test) == 0) { + usleep(1000 * global->test_options.update_msec); + t2 = odp_time_local(); + nsec = odp_time_diff_ns(t2, t1); + print_periodic_stat(global, nsec); + } +} + +static int print_final_stat(test_global_t *global) { int i, num_thr; double rx_pkt_ave, rx_mbit_per_sec, tx_mbit_per_sec; @@ -1378,6 +1476,10 @@ int main(int argc, char **argv) /* Wait until workers have started. */ odp_barrier_wait(&global->barrier); + /* Periodic statistics printing */ + if (global->test_options.update_msec) + periodic_print_loop(global); + /* Wait workers to exit */ odph_thread_join(global->thread_tbl, global->test_options.num_cpu); @@ -1390,7 +1492,7 @@ int main(int argc, char **argv) if (close_pktios(global)) ret = -1; - if (print_stat(global)) + if (print_final_stat(global)) ret = -2; term: diff --git a/test/performance/odp_pktio_ordered.c b/test/performance/odp_pktio_ordered.c index 46e6c1861..d5ffcc8ab 100644 --- a/test/performance/odp_pktio_ordered.c +++ b/test/performance/odp_pktio_ordered.c @@ -245,7 +245,7 @@ typedef struct { /** Global barrier to synchronize main and workers */ odp_barrier_t barrier; /** Break workers loop if set to 1 */ - int exit_threads; + odp_atomic_u32_t exit_threads; } args_t; /** Global pointer to args */ @@ -533,7 +533,7 @@ static int run_worker(void *arg) odp_barrier_wait(&gbl_args->barrier); /* Loop packets */ - while (!gbl_args->exit_threads) { + while (!odp_atomic_load_u32(&gbl_args->exit_threads)) { pkts = odp_schedule_multi(&queue, ODP_SCHED_NO_WAIT, ev_tbl, MAX_PKT_BURST); if (pkts <= 0) @@ -1034,6 +1034,7 @@ static void gbl_args_init(args_t *args) int pktio, queue; memset(args, 0, sizeof(args_t)); + odp_atomic_init_u32(&args->exit_threads, 0); for (pktio = 0; pktio < MAX_PKTIOS; pktio++) { args->pktios[pktio].pktio = ODP_PKTIO_INVALID; @@ -1320,7 +1321,7 @@ int main(int argc, char *argv[]) for (i = 0; i < if_count; i++) odp_pktio_stop(gbl_args->pktios[i].pktio); - gbl_args->exit_threads = 1; + odp_atomic_store_u32(&gbl_args->exit_threads, 1); /* Master thread waits for other threads to exit */ for (i = 0; i < num_workers; ++i) diff --git a/test/performance/odp_pktio_perf.c b/test/performance/odp_pktio_perf.c index f31f6146c..3418f62f4 100644 --- a/test/performance/odp_pktio_perf.c +++ b/test/performance/odp_pktio_perf.c @@ -822,7 +822,7 @@ static int test_init(void) static int empty_inq(odp_pktio_t pktio) { - odp_queue_t queue; + odp_queue_t queue = ODP_QUEUE_INVALID; odp_event_t ev; odp_queue_type_t q_type; diff --git a/test/performance/odp_sched_pktio.c b/test/performance/odp_sched_pktio.c index 8eb094873..fc814c541 100644 --- a/test/performance/odp_sched_pktio.c +++ b/test/performance/odp_sched_pktio.c @@ -1426,7 +1426,7 @@ int main(int argc, char *argv[]) odp_instance_t instance; odp_init_t init; odp_shm_t shm; - odp_time_t t1, t2; + odp_time_t t1 = ODP_TIME_NULL, t2 = ODP_TIME_NULL; odph_helper_options_t helper_options; odph_odpthread_t thread[MAX_WORKERS]; test_options_t test_options; diff --git a/test/validation/api/crypto/odp_crypto_test_inp.c b/test/validation/api/crypto/odp_crypto_test_inp.c index 1710c23e2..b14b3d484 100644 --- a/test/validation/api/crypto/odp_crypto_test_inp.c +++ b/test/validation/api/crypto/odp_crypto_test_inp.c @@ -514,10 +514,6 @@ static void check_alg(odp_crypto_op_t op, int rc, i; int cipher_num = odp_crypto_cipher_capability(cipher_alg, NULL, 0); int auth_num = odp_crypto_auth_capability(auth_alg, NULL, 0); - odp_crypto_cipher_capability_t cipher_capa[cipher_num]; - odp_crypto_auth_capability_t auth_capa[auth_num]; - odp_bool_t cipher_tested[cipher_num]; - odp_bool_t auth_tested[auth_num]; odp_bool_t cipher_ok = false; odp_bool_t auth_ok = false; size_t idx; @@ -525,6 +521,11 @@ static void check_alg(odp_crypto_op_t op, CU_ASSERT_FATAL(cipher_num > 0); CU_ASSERT_FATAL(auth_num > 0); + odp_crypto_cipher_capability_t cipher_capa[cipher_num]; + odp_crypto_auth_capability_t auth_capa[auth_num]; + odp_bool_t cipher_tested[cipher_num]; + odp_bool_t auth_tested[auth_num]; + rc = odp_crypto_capability(&capa); CU_ASSERT(!rc); diff --git a/test/validation/api/packet/packet.c b/test/validation/api/packet/packet.c index 6026ca32a..51d251630 100644 --- a/test/validation/api/packet/packet.c +++ b/test/validation/api/packet/packet.c @@ -862,7 +862,7 @@ static void _verify_headroom_shift(odp_packet_t *pkt, uint32_t room = odp_packet_headroom(*pkt); uint32_t seg_data_len = odp_packet_seg_len(*pkt); uint32_t pkt_data_len = odp_packet_len(*pkt); - void *data; + void *data = NULL; char *data_orig = odp_packet_data(*pkt); char *head_orig = odp_packet_head(*pkt); uint32_t seg_len; @@ -1571,7 +1571,7 @@ static void packet_test_concatsplit(void) { odp_packet_t pkt, pkt2; uint32_t pkt_len; - odp_packet_t splits[4]; + odp_packet_t splits[4] = {ODP_PACKET_INVALID}; odp_pool_t pool; pool = odp_packet_pool(test_packet); diff --git a/test/validation/api/pktio/parser.c b/test/validation/api/pktio/parser.c index 896855006..9c493b45e 100644 --- a/test/validation/api/pktio/parser.c +++ b/test/validation/api/pktio/parser.c @@ -56,7 +56,7 @@ static inline void wait_linkup(odp_pktio_t pktio) for (i = 0; i < wait_num; i++) { ret = odp_pktio_link_status(pktio); - if (ret < 0 || ret == 1) + if (ret == ODP_PKTIO_LINK_STATUS_UNKNOWN || ret == ODP_PKTIO_LINK_STATUS_UP) break; /* link is down, call status again after delay */ odp_time_wait_ns(wait_ns); diff --git a/test/validation/api/pktio/pktio.c b/test/validation/api/pktio/pktio.c index 20c33b461..4fa8f6d13 100644 --- a/test/validation/api/pktio/pktio.c +++ b/test/validation/api/pktio/pktio.c @@ -1,4 +1,5 @@ /* Copyright (c) 2014-2018, Linaro Limited + * Copyright (c) 2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -111,7 +112,7 @@ static inline void _pktio_wait_linkup(odp_pktio_t pktio) for (i = 0; i < wait_num; i++) { ret = odp_pktio_link_status(pktio); - if (ret < 0 || ret == 1) + if (ret == ODP_PKTIO_LINK_STATUS_UNKNOWN || ret == ODP_PKTIO_LINK_STATUS_UP) break; /* link is down, call status again after delay */ odp_time_wait_ns(wait_ns); @@ -649,7 +650,7 @@ static int recv_packets_tmo(odp_pktio_t pktio, odp_packet_t pkt_tbl[], int num_q; int i; int n; - unsigned from_val; + unsigned int from_val = 0; unsigned *from = NULL; if (mode == RECV_MQ_TMO) @@ -1480,6 +1481,44 @@ static void pktio_test_info(void) } } +static void pktio_test_link_info(void) +{ + odp_pktio_t pktio; + odp_pktio_link_info_t link_info; + int i; + + for (i = 0; i < num_ifaces; i++) { + memset(&link_info, 0, sizeof(link_info)); + + pktio = create_pktio(i, ODP_PKTIN_MODE_QUEUE, + ODP_PKTOUT_MODE_DIRECT); + CU_ASSERT_FATAL(pktio != ODP_PKTIO_INVALID); + + CU_ASSERT_FATAL(odp_pktio_link_info(pktio, &link_info) == 0); + + CU_ASSERT(link_info.autoneg == ODP_PKTIO_LINK_AUTONEG_UNKNOWN || + link_info.autoneg == ODP_PKTIO_LINK_AUTONEG_ON || + link_info.autoneg == ODP_PKTIO_LINK_AUTONEG_OFF); + CU_ASSERT(link_info.duplex == ODP_PKTIO_LINK_DUPLEX_UNKNOWN || + link_info.duplex == ODP_PKTIO_LINK_DUPLEX_HALF || + link_info.duplex == ODP_PKTIO_LINK_DUPLEX_FULL); + CU_ASSERT(link_info.pause_rx == ODP_PKTIO_LINK_PAUSE_UNKNOWN || + link_info.pause_rx == ODP_PKTIO_LINK_PAUSE_ON || + link_info.pause_rx == ODP_PKTIO_LINK_PAUSE_OFF); + CU_ASSERT(link_info.pause_tx == ODP_PKTIO_LINK_PAUSE_UNKNOWN || + link_info.pause_tx == ODP_PKTIO_LINK_PAUSE_ON || + link_info.pause_tx == ODP_PKTIO_LINK_PAUSE_OFF); + CU_ASSERT(link_info.status == ODP_PKTIO_LINK_STATUS_UNKNOWN || + link_info.status == ODP_PKTIO_LINK_STATUS_UP || + link_info.status == ODP_PKTIO_LINK_STATUS_DOWN); + CU_ASSERT(link_info.media != NULL); + + CU_ASSERT(odp_pktio_link_info(ODP_PKTIO_INVALID, &link_info) < 0); + + CU_ASSERT(odp_pktio_close(pktio) == 0); + } +} + static void pktio_test_pktin_queue_config_direct(void) { odp_pktio_t pktio; @@ -1745,7 +1784,7 @@ static void pktio_test_statistics_counters(void) pktio_tx = pktio[0]; pktio_rx = (num_ifaces > 1) ? pktio[1] : pktio_tx; - CU_ASSERT(odp_pktout_queue(pktio_tx, &pktout, 1) == 1); + CU_ASSERT_FATAL(odp_pktout_queue(pktio_tx, &pktout, 1) == 1); ret = odp_pktio_start(pktio_tx); CU_ASSERT(ret == 0); @@ -1849,7 +1888,7 @@ static void pktio_test_start_stop(void) CU_ASSERT_FATAL(pktio[i] != ODP_PKTIO_INVALID); } - CU_ASSERT(odp_pktout_queue(pktio[0], &pktout, 1) == 1); + CU_ASSERT_FATAL(odp_pktout_queue(pktio[0], &pktout, 1) == 1); /* Interfaces are stopped by default, * Check that stop when stopped generates an error */ @@ -2908,6 +2947,7 @@ odp_testinfo_t pktio_suite_unsegmented[] = { ODP_TEST_INFO(pktio_test_print), ODP_TEST_INFO(pktio_test_pktio_config), ODP_TEST_INFO(pktio_test_info), + ODP_TEST_INFO(pktio_test_link_info), ODP_TEST_INFO(pktio_test_pktin_queue_config_direct), ODP_TEST_INFO(pktio_test_pktin_queue_config_sched), ODP_TEST_INFO(pktio_test_pktin_queue_config_multi_sched), diff --git a/test/validation/api/pool/pool.c b/test/validation/api/pool/pool.c index 24b47d4fb..7ac92ff0e 100644 --- a/test/validation/api/pool/pool.c +++ b/test/validation/api/pool/pool.c @@ -83,6 +83,7 @@ static void pool_test_lookup_info_print(void) odp_pool_info_t info; odp_pool_param_t param; + memset(&info, 0, sizeof(info)); odp_pool_param_init(¶m); param.type = ODP_POOL_BUFFER; @@ -321,6 +322,7 @@ static void pool_test_info_packet(void) odp_pool_param_t param; const char pool_name[] = "test_pool_name"; + memset(&info, 0, sizeof(info)); odp_pool_param_init(¶m); param.type = ODP_POOL_PACKET; @@ -351,6 +353,7 @@ static void pool_test_info_data_range(void) uint32_t i, num; uintptr_t pool_len; + memset(&info, 0, sizeof(info)); odp_pool_param_init(¶m); param.type = ODP_POOL_PACKET; diff --git a/test/validation/api/queue/queue.c b/test/validation/api/queue/queue.c index 9b4ebd44c..a5ec628e4 100644 --- a/test/validation/api/queue/queue.c +++ b/test/validation/api/queue/queue.c @@ -580,8 +580,8 @@ static void queue_test_pair_lf_spsc(void) static void queue_test_param(void) { odp_queue_t queue, null_queue; - odp_event_t enev[BURST_SIZE]; - odp_event_t deev[BURST_SIZE]; + odp_event_t enev[BURST_SIZE] = {ODP_EVENT_INVALID}; + odp_event_t deev[BURST_SIZE] = {ODP_EVENT_INVALID}; odp_buffer_t buf; odp_event_t ev; odp_pool_t msg_pool; diff --git a/test/validation/api/random/random.c b/test/validation/api/random/random.c index cf7163e2d..481ceb303 100644 --- a/test/validation/api/random/random.c +++ b/test/validation/api/random/random.c @@ -9,11 +9,31 @@ static void random_test_get_size(void) { - int32_t ret; + /* odp_random_data may fail to return data on every call (i.e. lack of + * entropy). Therefore loop with some sane loop timeout value. Note that + * it is not required for implementation to return data in the "timeout" + * amount of steps. Rather it is a way for preventing the test to loop + * forever. + * Also note that the timeout value here is chosen completely + * arbitrarily (although considered sane) and neither platforms or + * applications are not required to use it. + */ + int32_t ret, timeout_ns = 1 * ODP_TIME_MSEC_IN_NS, sleep_ns = 100; + uint32_t bytes = 0; uint8_t buf[32]; - ret = odp_random_data(buf, sizeof(buf), ODP_RANDOM_BASIC); - CU_ASSERT(ret == sizeof(buf)); + do { + ret = odp_random_data(buf + bytes, sizeof(buf) - bytes, + ODP_RANDOM_BASIC); + bytes += ret; + if (ret < 0 || bytes >= sizeof(buf)) + break; + odp_time_wait_ns(sleep_ns); + timeout_ns -= sleep_ns; + } while (timeout_ns > 0); + + CU_ASSERT(ret > 0); + CU_ASSERT(bytes == (int32_t)sizeof(buf)); } static void random_test_kind(void) diff --git a/test/validation/api/time/time.c b/test/validation/api/time/time.c index 3add81976..2b1efa8af 100644 --- a/test/validation/api/time/time.c +++ b/test/validation/api/time/time.c @@ -26,6 +26,7 @@ static uint64_t global_res; typedef odp_time_t time_cb(void); typedef uint64_t time_res_cb(void); typedef odp_time_t time_from_ns_cb(uint64_t ns); +typedef uint64_t time_nsec_cb(void); static void time_test_constants(void) { @@ -120,10 +121,14 @@ static void time_test_monotony(void) volatile uint64_t count = 0; odp_time_t l_t1, l_t2, l_t3; odp_time_t g_t1, g_t2, g_t3; + uint64_t lns_t1, lns_t2, lns_t3; + uint64_t gns_t1, gns_t2, gns_t3; uint64_t ns1, ns2, ns3; l_t1 = odp_time_local(); g_t1 = odp_time_global(); + lns_t1 = odp_time_local_ns(); + gns_t1 = odp_time_global_ns(); while (count < BUSY_LOOP_CNT) { count++; @@ -131,6 +136,8 @@ static void time_test_monotony(void) l_t2 = odp_time_local(); g_t2 = odp_time_global(); + lns_t2 = odp_time_local_ns(); + gns_t2 = odp_time_global_ns(); while (count < BUSY_LOOP_CNT_LONG) { count++; @@ -138,6 +145,8 @@ static void time_test_monotony(void) l_t3 = odp_time_local(); g_t3 = odp_time_global(); + lns_t3 = odp_time_local_ns(); + gns_t3 = odp_time_global_ns(); ns1 = odp_time_to_ns(l_t1); ns2 = odp_time_to_ns(l_t2); @@ -154,6 +163,14 @@ static void time_test_monotony(void) /* Global time assertions */ CU_ASSERT(ns2 > ns1); CU_ASSERT(ns3 > ns2); + + /* Local time in nsec */ + CU_ASSERT(lns_t2 > lns_t1); + CU_ASSERT(lns_t3 > lns_t2); + + /* Global time in nsec */ + CU_ASSERT(gns_t2 > gns_t1); + CU_ASSERT(gns_t3 > gns_t2); } static void time_test_cmp(time_cb time_cur, time_from_ns_cb time_from_ns) @@ -481,6 +498,51 @@ static void time_test_global_accuracy(void) time_test_accuracy(odp_time_global, odp_time_global_from_ns); } +static void time_test_accuracy_nsec(time_nsec_cb time_nsec) +{ + uint64_t t1, t2, diff; + struct timespec ts1, ts2, tsdiff; + double sec_t, sec_c; + int i, ret; + + ret = clock_gettime(CLOCK_MONOTONIC, &ts1); + CU_ASSERT(ret == 0); + t1 = time_nsec(); + + for (i = 0; i < 5; i++) + odp_time_wait_ns(ODP_TIME_SEC_IN_NS); + + ret = clock_gettime(CLOCK_MONOTONIC, &ts2); + CU_ASSERT(ret == 0); + t2 = time_nsec(); + + if (ts2.tv_nsec < ts1.tv_nsec) { + tsdiff.tv_nsec = 1000000000L + ts2.tv_nsec - ts1.tv_nsec; + tsdiff.tv_sec = ts2.tv_sec - 1 - ts1.tv_sec; + } else { + tsdiff.tv_nsec = ts2.tv_nsec - ts1.tv_nsec; + tsdiff.tv_sec = ts2.tv_sec - ts1.tv_sec; + } + + diff = t2 - t1; + sec_t = ((double)diff) / ODP_TIME_SEC_IN_NS; + sec_c = ((double)(tsdiff.tv_nsec) / 1000000000L) + tsdiff.tv_sec; + + /* Check that ODP time is within +-5% of system time */ + CU_ASSERT(sec_t < sec_c * 1.05); + CU_ASSERT(sec_t > sec_c * 0.95); +} + +static void time_test_local_accuracy_nsec(void) +{ + time_test_accuracy_nsec(odp_time_local_ns); +} + +static void time_test_global_accuracy_nsec(void) +{ + time_test_accuracy_nsec(odp_time_global_ns); +} + odp_testinfo_t time_suite_time[] = { ODP_TEST_INFO(time_test_constants), ODP_TEST_INFO(time_test_local_res), @@ -499,6 +561,8 @@ odp_testinfo_t time_suite_time[] = { ODP_TEST_INFO(time_test_global_sum), ODP_TEST_INFO(time_test_global_wait_until), ODP_TEST_INFO(time_test_global_accuracy), + ODP_TEST_INFO(time_test_local_accuracy_nsec), + ODP_TEST_INFO(time_test_global_accuracy_nsec), ODP_TEST_INFO_NULL }; diff --git a/test/validation/api/timer/timer.c b/test/validation/api/timer/timer.c index b2c4b8964..09f8fc467 100644 --- a/test/validation/api/timer/timer.c +++ b/test/validation/api/timer/timer.c @@ -1,4 +1,5 @@ /* Copyright (c) 2015-2018, Linaro Limited + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -189,12 +190,20 @@ static void timer_test_capa(void) CU_ASSERT_FATAL(ret == 0); CU_ASSERT(capa.highest_res_ns == capa.max_res.res_ns); + /* Assuming max resoultion to be 100 msec or better */ + CU_ASSERT(capa.max_res.res_ns <= 100000000); + CU_ASSERT(capa.max_res.res_hz >= 10); CU_ASSERT(capa.max_res.res_ns < capa.max_res.max_tmo); CU_ASSERT(capa.max_res.min_tmo < capa.max_res.max_tmo); + + /* With max timeout, resolution may be low (worse than 1 sec) */ CU_ASSERT(capa.max_tmo.res_ns < capa.max_tmo.max_tmo); CU_ASSERT(capa.max_tmo.min_tmo < capa.max_tmo.max_tmo); + CU_ASSERT(capa.max_tmo.res_ns != 0 || capa.max_tmo.res_hz != 0); + if (capa.max_tmo.res_hz == 0) + CU_ASSERT(capa.max_tmo.res_ns > 1000000000); - /* Set max resolution */ + /* Set max resolution in nsec */ memset(&res_capa, 0, sizeof(res_capa)); res_capa.res_ns = capa.max_res.res_ns; @@ -204,6 +213,16 @@ static void timer_test_capa(void) CU_ASSERT(res_capa.min_tmo == capa.max_res.min_tmo); CU_ASSERT(res_capa.max_tmo == capa.max_res.max_tmo); + /* Set max resolution in hz */ + memset(&res_capa, 0, sizeof(res_capa)); + res_capa.res_hz = capa.max_res.res_hz; + + ret = odp_timer_res_capability(ODP_CLOCK_CPU, &res_capa); + CU_ASSERT_FATAL(ret == 0); + CU_ASSERT(res_capa.res_hz == capa.max_res.res_hz); + CU_ASSERT(res_capa.min_tmo == capa.max_res.min_tmo); + CU_ASSERT(res_capa.max_tmo == capa.max_res.max_tmo); + /* Set max timeout */ memset(&res_capa, 0, sizeof(res_capa)); res_capa.max_tmo = capa.max_tmo.max_tmo; @@ -213,6 +232,7 @@ static void timer_test_capa(void) CU_ASSERT(res_capa.max_tmo == capa.max_tmo.max_tmo); CU_ASSERT(res_capa.min_tmo == capa.max_tmo.min_tmo); CU_ASSERT(res_capa.res_ns == capa.max_tmo.res_ns); + CU_ASSERT(res_capa.res_hz == capa.max_tmo.res_hz); } static void timer_test_timeout_pool_alloc(void) @@ -367,6 +387,88 @@ static void timer_pool_create_destroy(void) CU_ASSERT(odp_queue_destroy(queue) == 0); } +static void timer_pool_max_res(void) +{ + odp_timer_capability_t capa; + odp_timer_pool_param_t tp_param; + odp_timer_pool_t tp; + odp_timer_t timer; + odp_pool_param_t pool_param; + odp_pool_t pool; + odp_queue_t queue; + odp_timeout_t tmo; + odp_event_t ev; + uint64_t tick; + int ret, i; + + memset(&capa, 0, sizeof(capa)); + ret = odp_timer_capability(ODP_CLOCK_CPU, &capa); + CU_ASSERT_FATAL(ret == 0); + + odp_pool_param_init(&pool_param); + pool_param.type = ODP_POOL_TIMEOUT; + pool_param.tmo.num = 10; + pool = odp_pool_create("timeout_pool", &pool_param); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + queue = odp_queue_create("timer_queue", NULL); + CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID); + + /* Highest resolution: first in nsec, then in hz */ + for (i = 0; i < 2; i++) { + memset(&tp_param, 0, sizeof(odp_timer_pool_param_t)); + + if (i == 0) { + printf("\n Highest resolution %" PRIu64 " nsec\n", + capa.max_res.res_ns); + tp_param.res_ns = capa.max_res.res_ns; + } else { + printf(" Highest resolution %" PRIu64 " Hz\n", + capa.max_res.res_hz); + tp_param.res_hz = capa.max_res.res_hz; + } + + tp_param.min_tmo = capa.max_res.min_tmo; + tp_param.max_tmo = capa.max_res.max_tmo; + tp_param.num_timers = 100; + tp_param.priv = 0; + tp_param.clk_src = ODP_CLOCK_CPU; + + tp = odp_timer_pool_create("high_res_tp", &tp_param); + CU_ASSERT_FATAL(tp != ODP_TIMER_POOL_INVALID); + + odp_timer_pool_start(); + + /* Maximum timeout length with maximum resolution */ + tick = odp_timer_ns_to_tick(tp, capa.max_res.max_tmo); + + timer = odp_timer_alloc(tp, queue, USER_PTR); + CU_ASSERT_FATAL(timer != ODP_TIMER_INVALID); + + tmo = odp_timeout_alloc(pool); + ev = odp_timeout_to_event(tmo); + CU_ASSERT_FATAL(ev != ODP_EVENT_INVALID); + + ret = odp_timer_set_rel(timer, tick, &ev); + CU_ASSERT(ret == ODP_TIMER_SUCCESS); + + ev = ODP_EVENT_INVALID; + ret = odp_timer_cancel(timer, &ev); + CU_ASSERT(ret == 0); + + if (ret == 0) { + CU_ASSERT(ev != ODP_EVENT_INVALID); + odp_event_free(ev); + } + + CU_ASSERT(odp_timer_free(timer) == ODP_EVENT_INVALID); + odp_timer_pool_destroy(tp); + } + + CU_ASSERT(odp_queue_destroy(queue) == 0); + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + static void timer_test_event_type(odp_queue_type_t queue_type, odp_event_type_t event_type) { @@ -566,6 +668,7 @@ static void timer_test_queue_type(odp_queue_type_t queue_type, int priv) res_ns = global_mem->param.res_ns; + memset(&tparam, 0, sizeof(odp_timer_pool_param_t)); tparam.res_ns = global_mem->param.res_ns; tparam.min_tmo = global_mem->param.min_tmo; tparam.max_tmo = global_mem->param.max_tmo; @@ -738,6 +841,7 @@ static void timer_test_cancel(void) if (pool == ODP_POOL_INVALID) CU_FAIL_FATAL("Timeout pool create failed"); + memset(&tparam, 0, sizeof(odp_timer_pool_param_t)); tparam.res_ns = global_mem->param.res_ns; tparam.min_tmo = global_mem->param.min_tmo; tparam.max_tmo = global_mem->param.max_tmo; @@ -1356,6 +1460,7 @@ static void timer_test_all(void) max_tmo = global_mem->param.max_tmo; min_tmo = global_mem->param.min_tmo; + memset(&tparam, 0, sizeof(odp_timer_pool_param_t)); tparam.res_ns = res_ns; tparam.min_tmo = min_tmo; tparam.max_tmo = max_tmo; @@ -1455,6 +1560,7 @@ odp_testinfo_t timer_suite[] = { ODP_TEST_INFO(timer_test_timeout_pool_alloc), ODP_TEST_INFO(timer_test_timeout_pool_free), ODP_TEST_INFO(timer_pool_create_destroy), + ODP_TEST_INFO(timer_pool_max_res), ODP_TEST_INFO(timer_test_tmo_event_plain), ODP_TEST_INFO(timer_test_tmo_event_sched), ODP_TEST_INFO(timer_test_buf_event_plain), diff --git a/test/validation/api/traffic_mngr/traffic_mngr.c b/test/validation/api/traffic_mngr/traffic_mngr.c index 2b0b99325..b5132bc12 100644 --- a/test/validation/api/traffic_mngr/traffic_mngr.c +++ b/test/validation/api/traffic_mngr/traffic_mngr.c @@ -456,7 +456,7 @@ static int wait_linkup(odp_pktio_t pktio) for (i = 0; i < wait_num; i++) { ret = odp_pktio_link_status(pktio); - if (ret < 0 || ret == 1) + if (ret == ODP_PKTIO_LINK_STATUS_UNKNOWN || ret == ODP_PKTIO_LINK_STATUS_UP) break; /* link is down, call status again after delay */ odp_time_wait_ns(wait_ns); @@ -1324,7 +1324,8 @@ static int create_tm_queue(odp_tm_t odp_tm, queue_desc->tm_queues[priority] = tm_queue; rc = odp_tm_queue_connect(tm_queue, tm_node); if (rc != 0) { - ODPH_ERR("odp_tm_queue_connect() failed\n"); + ODPH_ERR("odp_tm_queue_connect() failed for queue %" PRIx64 + "\n", odp_tm_queue_to_u64(tm_queue)); odp_tm_queue_destroy(tm_queue); return -1; } @@ -1652,7 +1653,8 @@ static int create_tm_system(void) /* Test odp_tm_capability and odp_tm_find. */ rc = odp_tm_capability(odp_tm, &tm_capabilities); if (rc != 0) { - ODPH_ERR("odp_tm_capability() failed\n"); + ODPH_ERR("odp_tm_capability() failed for tm: %" PRIx64 "\n", + odp_tm_to_u64(odp_tm)); return -1; } @@ -1677,7 +1679,7 @@ static void dump_tm_subtree(tm_node_desc_t *node_desc) rc = odp_tm_node_info(node_desc->node, &node_info); if (rc != 0) { ODPH_ERR("odp_tm_node_info failed for tm_node=0x%" PRIX64 "\n", - node_desc->node); + odp_tm_node_to_u64(node_desc->node)); } num_queues = 0; @@ -1688,8 +1690,9 @@ static void dump_tm_subtree(tm_node_desc_t *node_desc) "level=%" PRIu32" parent=0x%" PRIX64 " children=%" PRIu32 " " "queues=%" PRIu32 " queue_fanin=%" PRIu32 " " "node_fanin=%" PRIu32 "\n", - node_desc, node_desc->node_name, node_desc->node, - node_desc->node_idx, node_desc->level, node_desc->parent_node, + node_desc, node_desc->node_name, + odp_tm_node_to_u64(node_desc->node), node_desc->node_idx, + node_desc->level, odp_tm_node_to_u64(node_desc->parent_node), node_desc->num_children, num_queues, node_info.tm_queue_fanin, node_info.tm_node_fanin); @@ -1912,7 +1915,10 @@ static int destroy_all_shaper_profiles(void) rc = odp_tm_shaper_destroy(shaper_profile); if (rc != 0) { ODPH_ERR("odp_tm_sched_destroy failed " - "idx=%" PRIu32 " code=%d\n", idx, rc); + "node=%" PRIx64 " idx=%" PRIu32 + " code=%d\n", + odp_tm_shaper_to_u64(shaper_profile), + idx, rc); return rc; } shaper_profiles[idx] = ODP_TM_INVALID; @@ -1934,7 +1940,10 @@ static int destroy_all_sched_profiles(void) rc = odp_tm_sched_destroy(sched_profile); if (rc != 0) { ODPH_ERR("odp_tm_sched_destroy failed " - "idx=%" PRIu32 " code=%d\n", idx, rc); + "node=%" PRIx64 " idx=%" PRIu32 + " code=%d\n", + odp_tm_sched_to_u64(sched_profile), + idx, rc); return rc; } sched_profiles[idx] = ODP_TM_INVALID; @@ -1946,17 +1955,20 @@ static int destroy_all_sched_profiles(void) static int destroy_all_threshold_profiles(void) { - odp_tm_threshold_t threshold_profile; + odp_tm_threshold_t thr_profile; uint32_t idx; int rc; for (idx = 0; idx < NUM_THRESHOLD_PROFILES; idx++) { - threshold_profile = threshold_profiles[idx]; - if (threshold_profile != ODP_TM_INVALID) { - rc = odp_tm_threshold_destroy(threshold_profile); + thr_profile = threshold_profiles[idx]; + if (thr_profile != ODP_TM_INVALID) { + rc = odp_tm_threshold_destroy(thr_profile); if (rc != 0) { ODPH_ERR("odp_tm_threshold_destroy failed " - "idx=%" PRIu32 " code=%d\n", idx, rc); + "node=%" PRIx64 " idx=%" PRIu32 + " code=%d\n", + odp_tm_threshold_to_u64(thr_profile), + idx, rc); return rc; } threshold_profiles[idx] = ODP_TM_INVALID; @@ -1968,19 +1980,20 @@ static int destroy_all_threshold_profiles(void) static int destroy_all_wred_profiles(void) { - odp_tm_wred_t wred_profile; + odp_tm_wred_t wred_prof; uint32_t idx, color; int rc; for (idx = 0; idx < NUM_WRED_PROFILES; idx++) { for (color = 0; color < ODP_NUM_PKT_COLORS; color++) { - wred_profile = wred_profiles[idx][color]; - if (wred_profile != ODP_TM_INVALID) { - rc = odp_tm_wred_destroy(wred_profile); + wred_prof = wred_profiles[idx][color]; + if (wred_prof != ODP_TM_INVALID) { + rc = odp_tm_wred_destroy(wred_prof); if (rc != 0) { ODPH_ERR("odp_tm_wred_destroy failed " - "idx=%" PRIu32 " " - "color=%" PRIu32 " code=%d\n", + "node=%" PRIx64 " idx=%" PRIu32 + " color=%" PRIu32 " code=%d\n", + odp_tm_wred_to_u64(wred_prof), idx, color, rc); return rc; } @@ -2114,6 +2127,7 @@ static void check_shaper_profile(char *shaper_name, uint32_t shaper_idx) { odp_tm_shaper_params_t shaper_params; odp_tm_shaper_t profile; + int rc; profile = odp_tm_shaper_lookup(shaper_name); CU_ASSERT(profile != ODP_TM_INVALID); @@ -2121,7 +2135,9 @@ static void check_shaper_profile(char *shaper_name, uint32_t shaper_idx) if (profile != shaper_profiles[shaper_idx - 1]) return; - odp_tm_shaper_params_read(profile, &shaper_params); + memset(&shaper_params, 0, sizeof(shaper_params)); + rc = odp_tm_shaper_params_read(profile, &shaper_params); + CU_ASSERT(rc == 0); CU_ASSERT(approx_eq64(shaper_params.commit_bps, shaper_idx * MIN_COMMIT_BW)); CU_ASSERT(approx_eq64(shaper_params.peak_bps, @@ -2211,7 +2227,7 @@ static void traffic_mngr_test_sched_profile(void) for (idx = 1; idx <= NUM_SCHED_TEST_PROFILES; idx++) { snprintf(sched_name, sizeof(sched_name), "sched_profile_%" PRIu32, idx); - for (priority = 0; priority < 16; priority++) { + for (priority = 0; priority < ODP_TM_MAX_PRIORITIES; priority++) { sched_params.sched_modes[priority] = ODP_TM_BYTE_BASED_WEIGHTS; sched_params.sched_weights[priority] = 8 + idx + @@ -3276,6 +3292,7 @@ static int test_query_functions(const char *shaper_name, expected_pkt_cnt = num_pkts - 2; expected_byte_cnt = expected_pkt_cnt * PKT_BUF_SIZE; + memset(&query_info, 0, sizeof(query_info)); rc = odp_tm_queue_query(tm_queue, ODP_TM_QUERY_PKT_CNT | ODP_TM_QUERY_BYTE_CNT, &query_info); @@ -3285,6 +3302,7 @@ static int test_query_functions(const char *shaper_name, CU_ASSERT(query_info.total_byte_cnt_valid); CU_ASSERT(expected_byte_cnt < query_info.total_byte_cnt); + memset(&query_info, 0, sizeof(query_info)); rc = odp_tm_priority_query(odp_tm_systems[0], priority, ODP_TM_QUERY_PKT_CNT | ODP_TM_QUERY_BYTE_CNT, &query_info); @@ -3294,6 +3312,7 @@ static int test_query_functions(const char *shaper_name, CU_ASSERT(query_info.total_byte_cnt_valid); CU_ASSERT(expected_byte_cnt < query_info.total_byte_cnt); + memset(&query_info, 0, sizeof(query_info)); rc = odp_tm_total_query(odp_tm_systems[0], ODP_TM_QUERY_PKT_CNT | ODP_TM_QUERY_BYTE_CNT, &query_info); @@ -3771,7 +3790,7 @@ static int walk_tree_backwards(odp_tm_node_t tm_node) rc = odp_tm_node_info(tm_node, &node_info); if (rc != 0) { ODPH_ERR("odp_tm_node_info failed for tm_node=0x%" PRIX64 "\n", - tm_node); + odp_tm_node_to_u64(tm_node)); return rc; } |