diff --git a/app/test/Makefile b/app/test/Makefile
index b28bed2..54f7067 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -96,6 +96,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_STACK) += test_stack_perf.c
 SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer.c
 SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer_perf.c
 SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer_racecond.c
+SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer_secondary.c
 
 SRCS-y += test_mempool.c
 SRCS-y += test_mempool_perf.c
diff --git a/app/test/meson.build b/app/test/meson.build
index 5e056eb..80cdea5 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -109,6 +109,7 @@ test_sources = files('commands.c',
 	'test_timer.c',
 	'test_timer_perf.c',
 	'test_timer_racecond.c',
+	'test_timer_secondary.c',
 	'test_ticketlock.c',
 	'test_version.c',
 	'virtual_pmd.c'
diff --git a/app/test/test.c b/app/test/test.c
index 1c91ed6..fbe4464 100644
--- a/app/test/test.c
+++ b/app/test/test.c
@@ -67,6 +67,7 @@ do_recursive_call(void)
 			{ "test_memory_flags", no_action },
 			{ "test_file_prefix", no_action },
 			{ "test_no_huge_flag", no_action },
+			{ "timer_secondary_spawn_wait", test_timer_secondary },
 	};
 
 	if (recursive_call == NULL)
@@ -130,7 +131,10 @@ main(int argc, char **argv)
 	}
 
 #ifdef RTE_LIBRTE_TIMER
-	rte_timer_subsystem_init();
+	if (rte_timer_subsystem_init() < 0) {
+		ret = -1;
+		goto out;
+	}
 #endif
 
 	if (commands_init() < 0) {
diff --git a/app/test/test.h b/app/test/test.h
index 9b3846b..ac0c506 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -156,6 +156,7 @@ extern const char *prgname;
 int commands_init(void);
 
 int test_mp_secondary(void);
+int test_timer_secondary(void);
 
 int test_set_rxtx_conf(cmdline_fixed_string_t mode);
 int test_set_rxtx_anchor(cmdline_fixed_string_t type);
diff --git a/app/test/test_timer_secondary.c b/app/test/test_timer_secondary.c
new file mode 100644
index 0000000..31e4a7f
--- /dev/null
+++ b/app/test/test_timer_secondary.c
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <rte_eal.h>
+#include <rte_lcore.h>
+#include <rte_debug.h>
+#include <rte_memzone.h>
+#include <rte_atomic.h>
+#include <rte_timer.h>
+#include <rte_cycles.h>
+#include <rte_mempool.h>
+#include <rte_random.h>
+
+#include "test.h"
+#include "process.h"
+
+#define NUM_TIMERS		(1 << 20) /* ~1M timers */
+#define NUM_LCORES_NEEDED	3
+#define TEST_INFO_MZ_NAME	"test_timer_info_mz"
+#define MSECPERSEC		1E3
+
+#define launch_proc(ARGV) \
+	process_dup(ARGV, sizeof(ARGV)/(sizeof(ARGV[0])), __func__)
+
+struct test_info {
+	unsigned int mstr_lcore;
+	unsigned int mgr_lcore;
+	unsigned int sec_lcore;
+	uint32_t timer_data_id;
+	volatile int expected_count;
+	volatile int expired_count;
+	struct rte_mempool *tim_mempool;
+	struct rte_timer *expired_timers[NUM_TIMERS];
+	int expired_timers_idx;
+	volatile int exit_flag;
+};
+
+static int
+timer_secondary_spawn_wait(unsigned int lcore)
+{
+	char coremask[10];
+#ifdef RTE_EXEC_ENV_LINUXAPP
+	char tmp[PATH_MAX] = {0};
+	char prefix[PATH_MAX] = {0};
+
+	get_current_prefix(tmp, sizeof(tmp));
+
+	snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp);
+#else
+	const char *prefix = "";
+#endif
+	char const *argv[] = {
+		prgname,
+		"-c", coremask,
+		"--proc-type=secondary",
+		prefix
+	};
+
+	snprintf(coremask, sizeof(coremask), "%x", (1 << lcore));
+
+	return launch_proc(argv);
+}
+
+static void
+handle_expired_timer(struct rte_timer *tim)
+{
+	struct test_info *test_info = tim->arg;
+
+	test_info->expired_count++;
+	test_info->expired_timers[test_info->expired_timers_idx++] = tim;
+}
+
+static int
+timer_manage_loop(void *arg)
+{
+#define TICK_MSECS 1
+	uint64_t tick_cycles = TICK_MSECS * rte_get_timer_hz() / MSECPERSEC;
+	uint64_t prev_tsc = 0, cur_tsc, diff_tsc;
+	struct test_info *test_info = arg;
+
+	while (!test_info->exit_flag) {
+		cur_tsc = rte_rdtsc();
+		diff_tsc = cur_tsc - prev_tsc;
+
+		if (diff_tsc > tick_cycles) {
+			/* Scan timer list for expired timers */
+			rte_timer_alt_manage(test_info->timer_data_id,
+					     NULL,
+					     0,
+					     handle_expired_timer);
+
+			/* Return expired timer objects back to mempool */
+			rte_mempool_put_bulk(test_info->tim_mempool,
+					     (void **)test_info->expired_timers,
+					     test_info->expired_timers_idx);
+
+			test_info->expired_timers_idx = 0;
+
+			prev_tsc = cur_tsc;
+		}
+
+		rte_pause();
+	}
+
+	return 0;
+}
+
+int
+test_timer_secondary(void)
+{
+	int proc_type = rte_eal_process_type();
+	const struct rte_memzone *mz;
+	struct test_info *test_info;
+	int ret;
+
+	if (proc_type == RTE_PROC_PRIMARY) {
+		mz = rte_memzone_reserve(TEST_INFO_MZ_NAME, sizeof(*test_info),
+					 SOCKET_ID_ANY, 0);
+		test_info = mz->addr;
+		TEST_ASSERT_NOT_NULL(test_info, "Couldn't allocate memory for "
+				     "test data");
+
+		TEST_ASSERT(rte_lcore_count() >= NUM_LCORES_NEEDED,
+			    "at least %d lcores needed to run tests",
+			    NUM_LCORES_NEEDED);
+
+		test_info->tim_mempool = rte_mempool_create("test_timer_mp",
+				NUM_TIMERS, sizeof(struct rte_timer), 0, 0,
+				NULL, NULL, NULL, NULL, rte_socket_id(), 0);
+
+		ret = rte_timer_data_alloc(&test_info->timer_data_id);
+		TEST_ASSERT_SUCCESS(ret, "Failed to allocate timer data "
+				    "instance");
+
+		unsigned int *mstr_lcorep = &test_info->mstr_lcore;
+		unsigned int *mgr_lcorep = &test_info->mgr_lcore;
+		unsigned int *sec_lcorep = &test_info->sec_lcore;
+
+		*mstr_lcorep = rte_get_master_lcore();
+		*mgr_lcorep = rte_get_next_lcore(*mstr_lcorep, 1, 1);
+		*sec_lcorep = rte_get_next_lcore(*mgr_lcorep, 1, 1);
+
+		ret = rte_eal_remote_launch(timer_manage_loop,
+					    (void *)test_info,
+					    *mgr_lcorep);
+		TEST_ASSERT_SUCCESS(ret, "Failed to launch timer manage loop");
+
+		ret = timer_secondary_spawn_wait(*sec_lcorep);
+		TEST_ASSERT_SUCCESS(ret, "Secondary process execution failed");
+
+		rte_delay_ms(2000);
+
+		test_info->exit_flag = 1;
+		rte_eal_wait_lcore(*mgr_lcorep);
+
+#ifdef RTE_LIBRTE_TIMER_DEBUG
+		rte_timer_alt_dump_stats(test_info->timer_data_id, stdout);
+#endif
+
+		return test_info->expected_count == test_info->expired_count ?
+			TEST_SUCCESS : TEST_FAILED;
+
+	} else if (proc_type == RTE_PROC_SECONDARY) {
+		uint64_t ticks, timeout_ms;
+		struct rte_timer *tim;
+		int i;
+
+		mz = rte_memzone_lookup(TEST_INFO_MZ_NAME);
+		test_info = mz->addr;
+		TEST_ASSERT_NOT_NULL(test_info, "Couldn't lookup memzone for "
+				     "test info");
+
+		for (i = 0; i < NUM_TIMERS; i++) {
+			rte_mempool_get(test_info->tim_mempool, (void **)&tim);
+
+			rte_timer_init(tim);
+
+			/* generate timeouts between 10 and 160 ms */
+			timeout_ms = ((rte_rand() & 0xF) + 1) * 10;
+			ticks = timeout_ms * rte_get_timer_hz() / MSECPERSEC;
+
+			ret = rte_timer_alt_reset(test_info->timer_data_id,
+						  tim, ticks, SINGLE,
+						  test_info->mgr_lcore, NULL,
+						  test_info);
+			if (ret < 0)
+				return TEST_FAILED;
+
+			test_info->expected_count++;
+
+			/* randomly leave timer running or stop it */
+			if (rte_rand() & 1)
+				continue;
+
+			ret = rte_timer_alt_stop(test_info->timer_data_id,
+						 tim);
+			if (ret == 0) {
+				test_info->expected_count--;
+				rte_mempool_put(test_info->tim_mempool,
+						(void *)tim);
+			}
+
+		}
+
+		return TEST_SUCCESS;
+	}
+
+	return TEST_FAILED;
+}
+
+REGISTER_TEST_COMMAND(timer_secondary_autotest, test_timer_secondary);
diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index ae5d236..eb46009 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -582,11 +582,6 @@ rte_timer_alt_reset(uint32_t timer_data_id, struct rte_timer *tim,
 
 	TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
 
-	if (unlikely((tim_lcore != (unsigned int)LCORE_ID_ANY) &&
-			!(rte_lcore_is_enabled(tim_lcore) ||
-			  rte_lcore_has_role(tim_lcore, ROLE_SERVICE))))
-		return -1;
-
 	if (type == PERIODICAL)
 		period = ticks;
 	else
