net: ptp: clock: Add usermode support to ptp_clock_get()

It is useful that the ptp_clock_get() function can be called from
the userspace. Create also unit test for calling that function
from userspace.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt
index aa770c1..57acca6 100644
--- a/drivers/CMakeLists.txt
+++ b/drivers/CMakeLists.txt
@@ -43,3 +43,4 @@
 add_subdirectory_ifdef(CONFIG_ENTROPY_HAS_DRIVER entropy)
 add_subdirectory_ifdef(CONFIG_SYS_CLOCK_EXISTS timer)
 add_subdirectory_ifdef(CONFIG_NEURAL_NET_ACCEL neural_net)
+add_subdirectory_ifdef(CONFIG_PTP_CLOCK        ptp_clock)
diff --git a/drivers/ptp_clock/CMakeLists.txt b/drivers/ptp_clock/CMakeLists.txt
new file mode 100644
index 0000000..6ece304
--- /dev/null
+++ b/drivers/ptp_clock/CMakeLists.txt
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: Apache-2.0
+
+zephyr_sources_ifdef(CONFIG_PTP_CLOCK ptp_clock.c)
diff --git a/drivers/ptp_clock/ptp_clock.c b/drivers/ptp_clock/ptp_clock.c
new file mode 100644
index 0000000..ce9ce02
--- /dev/null
+++ b/drivers/ptp_clock/ptp_clock.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019 Intel Corporation.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <syscall_handler.h>
+#include <ptp_clock.h>
+
+#ifdef CONFIG_USERSPACE
+Z_SYSCALL_HANDLER(ptp_clock_get, dev, tm)
+{
+	struct net_ptp_time ptp_time;
+	int ret;
+
+	Z_OOPS(Z_SYSCALL_DRIVER_PTP_CLOCK(dev, get));
+	Z_OOPS(Z_SYSCALL_MEMORY_WRITE(tm, sizeof(struct net_ptp_time)));
+
+	ret = z_impl_ptp_clock_get((struct device *)dev, &ptp_time);
+	if (ret != 0) {
+		return 0;
+	}
+
+	if (z_user_to_copy((void *)tm, &ptp_time, sizeof(ptp_time)) != 0) {
+		return 0;
+	}
+
+	return (u32_t)ret;
+}
+#endif /* CONFIG_USERSPACE */
diff --git a/include/ptp_clock.h b/include/ptp_clock.h
index 68120b9..edb9084 100644
--- a/include/ptp_clock.h
+++ b/include/ptp_clock.h
@@ -7,6 +7,7 @@
 #ifndef ZEPHYR_INCLUDE_PTP_CLOCK_H_
 #define ZEPHYR_INCLUDE_PTP_CLOCK_H_
 
+#include <kernel.h>
 #include <stdint.h>
 #include <device.h>
 #include <misc/util.h>
@@ -51,7 +52,10 @@
  *
  * @return 0 if ok, <0 if error
  */
-static inline int ptp_clock_get(struct device *dev, struct net_ptp_time *tm)
+__syscall int ptp_clock_get(struct device *dev, struct net_ptp_time *tm);
+
+static inline int z_impl_ptp_clock_get(struct device *dev,
+				       struct net_ptp_time *tm)
 {
 	const struct ptp_clock_driver_api *api = dev->driver_api;
 
@@ -88,6 +92,8 @@
 	return api->rate_adjust(dev, rate);
 }
 
+#include <syscalls/ptp_clock.h>
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/scripts/gen_kobject_list.py b/scripts/gen_kobject_list.py
index d4aa54d..8cf04ab 100755
--- a/scripts/gen_kobject_list.py
+++ b/scripts/gen_kobject_list.py
@@ -112,6 +112,7 @@
     "spi_driver_api",
     "uart_driver_api",
     "can_driver_api",
+    "ptp_clock_driver_api",
 ]
 
 
diff --git a/tests/net/ptp/clock/src/main.c b/tests/net/ptp/clock/src/main.c
index 1ca2d06..88e45d3 100644
--- a/tests/net/ptp/clock/src/main.c
+++ b/tests/net/ptp/clock/src/main.c
@@ -394,6 +394,7 @@
 
 static void test_ptp_clock_interfaces(void)
 {
+	struct device *clk_by_index;
 	struct device *clk;
 	int idx;
 
@@ -410,6 +411,11 @@
 	clk = net_eth_get_ptp_clock(eth_interfaces[non_ptp_interface]);
 	zassert_is_null(clk, "Clock found for interface %p\n",
 			eth_interfaces[non_ptp_interface]);
+
+	clk_by_index = net_eth_get_ptp_clock_by_index(ptp_clocks[0]);
+	zassert_not_null(clk_by_index,
+			 "Clock not found for interface index %d\n",
+			 ptp_clocks[0]);
 }
 
 static void test_ptp_clock_iface(int idx)
@@ -504,8 +510,51 @@
 	zassert_equal(clk1, clk_by_index, "Invalid PTP clock 1");
 }
 
+static ZTEST_BMEM struct net_ptp_time tm;
+static ZTEST_BMEM struct net_ptp_time empty;
+
+static void test_ptp_clock_get_by_xxx(const char *who)
+{
+	struct device *clk_by_index;
+	int ret;
+
+	clk_by_index = net_eth_get_ptp_clock_by_index(ptp_clocks[0]);
+	zassert_not_null(clk_by_index, "PTP 0 not found (%s)", who);
+	zassert_equal(clk0, clk_by_index, "Invalid PTP clock 0 (%s)", who);
+
+	(void)memset(&tm, 0, sizeof(tm));
+	ptp_clock_get(clk_by_index, &tm);
+
+	ret = memcmp(&tm, &empty, sizeof(tm));
+	zassert_not_equal(ret, 0, "ptp_clock_get() failed in %s mode", who);
+}
+
+static void test_ptp_clock_get_kernel(void)
+{
+	struct device *clk;
+
+	/* Make sure that this function is really run in kernel mode by
+	 * calling a function that will not work in user mode.
+	 */
+	clk = net_eth_get_ptp_clock(eth_interfaces[0]);
+
+	test_ptp_clock_get_by_xxx("kernel");
+}
+
+static void test_ptp_clock_get_user(void)
+{
+	test_ptp_clock_get_by_xxx("user");
+}
+
 void test_main(void)
 {
+	struct device *clk;
+
+	clk = device_get_binding(PTP_CLOCK_NAME);
+	if (clk != NULL) {
+		k_object_access_grant(clk, k_current_get());
+	}
+
 	ztest_test_suite(ptp_clock_test,
 			 ztest_unit_test(check_interfaces),
 			 ztest_unit_test(address_setup),
@@ -513,7 +562,9 @@
 			 ztest_unit_test(test_ptp_clock_iface_1),
 			 ztest_unit_test(test_ptp_clock_iface_2),
 			 ztest_unit_test(test_ptp_clock_get_by_index),
-			 ztest_user_unit_test(test_ptp_clock_get_by_index_user)
+			 ztest_user_unit_test(test_ptp_clock_get_by_index_user),
+			 ztest_unit_test(test_ptp_clock_get_kernel),
+			 ztest_user_unit_test(test_ptp_clock_get_user)
 			 );
 
 	ztest_run_test_suite(ptp_clock_test);
diff --git a/tests/net/ptp/clock/testcase.yaml b/tests/net/ptp/clock/testcase.yaml
index fa33ec5..c0eb38c 100644
--- a/tests/net/ptp/clock/testcase.yaml
+++ b/tests/net/ptp/clock/testcase.yaml
@@ -1,6 +1,5 @@
 common:
   depends_on: netif
-  platform_whitelist: native_posix qemu_x86 qemu_cortex_m3
 tests:
   net.ptp.clock:
     min_ram: 32