summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/configs/msm-auto-perf_defconfig1
-rw-r--r--arch/arm64/configs/msm-auto_defconfig1
-rw-r--r--drivers/soc/qcom/hab/hab.c8
-rw-r--r--drivers/soc/qcom/hab/hab.h4
-rw-r--r--drivers/soc/qcom/hab/hab_msg.c16
-rw-r--r--drivers/soc/qcom/hab/qvm_comm.c12
-rw-r--r--include/linux/habmm.h31
-rw-r--r--kernel/time/timekeeping.c31
8 files changed, 100 insertions, 4 deletions
diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig
index fe6727a1eb25..54f46ac4dbf4 100644
--- a/arch/arm64/configs/msm-auto-perf_defconfig
+++ b/arch/arm64/configs/msm-auto-perf_defconfig
@@ -519,6 +519,7 @@ CONFIG_SEEMP_CORE=y
CONFIG_USB_BAM=y
CONFIG_MSM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_TIMER_LEAP=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_ARM_SMMU=y
CONFIG_IOMMU_DEBUG=y
diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig
index 2b1b13c992e7..eb8a244aef6d 100644
--- a/arch/arm64/configs/msm-auto_defconfig
+++ b/arch/arm64/configs/msm-auto_defconfig
@@ -525,6 +525,7 @@ CONFIG_SEEMP_CORE=y
CONFIG_USB_BAM=y
CONFIG_MSM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_TIMER_LEAP=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
CONFIG_ARM_SMMU=y
diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c
index 24461d2c957b..b6dfe2d9ae22 100644
--- a/drivers/soc/qcom/hab/hab.c
+++ b/drivers/soc/qcom/hab/hab.c
@@ -566,6 +566,14 @@ long hab_vchan_send(struct uhab_context *ctx,
sizeof(struct habmm_xing_vm_stat));
return -EINVAL;
}
+ } else if (flags & HABMM_SOCKET_XVM_SCHE_TEST) {
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_SCHE_MSG);
+ } else if (flags & HABMM_SOCKET_XVM_SCHE_TEST_ACK) {
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_SCHE_MSG_ACK);
+ } else if (flags & HABMM_SOCKET_XVM_SCHE_RESULT_REQ) {
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_SCHE_RESULT_REQ);
+ } else if (flags & HABMM_SOCKET_XVM_SCHE_RESULT_RSP) {
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_SCHE_RESULT_RSP);
} else {
HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_MSG);
}
diff --git a/drivers/soc/qcom/hab/hab.h b/drivers/soc/qcom/hab/hab.h
index a2df3b64cce6..7d0c5f2673a2 100644
--- a/drivers/soc/qcom/hab/hab.h
+++ b/drivers/soc/qcom/hab/hab.h
@@ -58,6 +58,10 @@ enum hab_payload_type {
HAB_PAYLOAD_TYPE_PROFILE,
HAB_PAYLOAD_TYPE_CLOSE,
HAB_PAYLOAD_TYPE_INIT_CANCEL,
+ HAB_PAYLOAD_TYPE_SCHE_MSG,
+ HAB_PAYLOAD_TYPE_SCHE_MSG_ACK,
+ HAB_PAYLOAD_TYPE_SCHE_RESULT_REQ,
+ HAB_PAYLOAD_TYPE_SCHE_RESULT_RSP,
HAB_PAYLOAD_TYPE_MAX,
};
#define LOOPBACK_DOM 0xFF
diff --git a/drivers/soc/qcom/hab/hab_msg.c b/drivers/soc/qcom/hab/hab_msg.c
index 40ff1a9d6415..e0f4970ce14e 100644
--- a/drivers/soc/qcom/hab/hab_msg.c
+++ b/drivers/soc/qcom/hab/hab_msg.c
@@ -206,6 +206,7 @@ int hab_msg_recv(struct physical_channel *pchan,
struct virtual_channel *vchan = NULL;
struct export_desc *exp_desc;
struct timeval tv;
+ unsigned long long rx_mpm_tv;
/* get the local virtual channel if it isn't an open message */
if (payload_type != HAB_PAYLOAD_TYPE_INIT &&
@@ -262,6 +263,8 @@ int hab_msg_recv(struct physical_channel *pchan,
switch (payload_type) {
case HAB_PAYLOAD_TYPE_MSG:
+ case HAB_PAYLOAD_TYPE_SCHE_RESULT_REQ:
+ case HAB_PAYLOAD_TYPE_SCHE_RESULT_RSP:
message = hab_msg_alloc(pchan, sizebytes);
if (!message)
break;
@@ -357,6 +360,19 @@ int hab_msg_recv(struct physical_channel *pchan,
}
break;
+ case HAB_PAYLOAD_TYPE_SCHE_MSG:
+ case HAB_PAYLOAD_TYPE_SCHE_MSG_ACK:
+ rx_mpm_tv = msm_timer_get_sclk_ticks();
+ /* pull down the incoming data */
+ message = hab_msg_alloc(pchan, sizebytes);
+ if (!message)
+ pr_err("failed to allocate msg Arrived msg will be lost\n");
+ else {
+ ((unsigned long long *)message->data)[0] = rx_mpm_tv;
+ hab_msg_queue(vchan, message);
+ }
+ break;
+
default:
pr_err("unknown msg received, payload type %d, vchan id %x, sizebytes %zx, session %d\n",
payload_type, vchan_id, sizebytes, session_id);
diff --git a/drivers/soc/qcom/hab/qvm_comm.c b/drivers/soc/qcom/hab/qvm_comm.c
index ab57f2758aed..25d0208dea4c 100644
--- a/drivers/soc/qcom/hab/qvm_comm.c
+++ b/drivers/soc/qcom/hab/qvm_comm.c
@@ -13,6 +13,8 @@
#include "hab.h"
#include "hab_qvm.h"
+static unsigned long long xvm_sche_tx_tv_buffer[2];
+
inline void habhyp_notify(void *commdev)
{
struct qvm_channel *dev = (struct qvm_channel *)commdev;
@@ -79,6 +81,12 @@ int physical_channel_send(struct physical_channel *pchan,
spin_unlock_bh(&dev->io_lock);
return -EINVAL;
}
+ } else if (HAB_HEADER_GET_TYPE(*header)
+ == HAB_PAYLOAD_TYPE_SCHE_RESULT_REQ) {
+ ((unsigned long long *)payload)[0] = xvm_sche_tx_tv_buffer[0];
+ } else if (HAB_HEADER_GET_TYPE(*header)
+ == HAB_PAYLOAD_TYPE_SCHE_RESULT_RSP) {
+ ((unsigned long long *)payload)[2] = xvm_sche_tx_tv_buffer[1];
}
if (sizebytes) {
@@ -92,6 +100,10 @@ int physical_channel_send(struct physical_channel *pchan,
hab_pipe_write_commit(dev->pipe_ep);
spin_unlock_bh(&dev->io_lock);
+ if (HAB_HEADER_GET_TYPE(*header) == HAB_PAYLOAD_TYPE_SCHE_MSG)
+ xvm_sche_tx_tv_buffer[0] = msm_timer_get_sclk_ticks();
+ else if (HAB_HEADER_GET_TYPE(*header) == HAB_PAYLOAD_TYPE_SCHE_MSG_ACK)
+ xvm_sche_tx_tv_buffer[1] = msm_timer_get_sclk_ticks();
habhyp_notify(dev);
++pchan->sequence_tx;
return 0;
diff --git a/include/linux/habmm.h b/include/linux/habmm.h
index cd4e2506f9ee..34ba1083a554 100644
--- a/include/linux/habmm.h
+++ b/include/linux/habmm.h
@@ -105,6 +105,37 @@ int32_t habmm_socket_close(int32_t handle);
*/
#define HABMM_SOCKET_SEND_FLAGS_XING_VM_STAT 0x00000002
+/* start to measure cross-vm schedule latency: VM1 send msg with this flag
+ * to VM2 to kick off the measurement. In the hab driver level, the VM1 hab
+ * driver shall record the time of schdule out with mpm_timer, and buffer
+ * it for later usage. The VM2 hab driver shall record the time of schedule
+ * in with mpm_timer and pass it to "habtest" application.
+ */
+#define HABMM_SOCKET_XVM_SCHE_TEST 0x00000004
+
+/* VM2 responds this message to VM1 for HABMM_SOCKET_XVM_SCHE_TEST.
+ * In the hab driver level, the VM2 hab driver shall record the time of schedule
+ * out with mpm_timer, and buffer it for later usage; the VM1 hab driver
+ * shall record the time of schedule in with mpm_timer and pass it to "habtest"
+ * application.
+ */
+#define HABMM_SOCKET_XVM_SCHE_TEST_ACK 0x00000008
+
+/* VM1 sends this message to VM2 asking for collect all the mpm_timer values
+ * to calculate the latency of schduling between VM1 and VM2. In the hab driver
+ * level, the VM1 hab driver shall save the previous restored schduling out
+ * time to the message buffer
+ */
+#define HABMM_SOCKET_XVM_SCHE_RESULT_REQ 0x00000010
+
+/* VM2 responds this message to VM2 for HABMM_SOCKET_XVM_SCHE_RESULT_REQ.
+ * In the habtest application level, VM2 shall save the previous restored
+ * scheduling in time into message buffer, in the hab driver level, VM2
+ * shall save the previous restored scheduling out time to the message
+ * buffer.
+ */
+#define HABMM_SOCKET_XVM_SCHE_RESULT_RSP 0x00000020
+
struct habmm_xing_vm_stat {
uint64_t tx_sec;
uint64_t tx_usec;
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 7902ecbce8ec..0651c7f47932 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1669,9 +1669,12 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,
{
s64 interval = tk->cycle_interval;
s64 xinterval = tk->xtime_interval;
+ u32 base = tk->tkr_mono.clock->mult;
+ u32 max = tk->tkr_mono.clock->maxadj;
+ u32 cur_adj = tk->tkr_mono.mult;
s64 tick_error;
bool negative;
- u32 adj;
+ u32 adj_scale;
/* Remove any current error adj from freq calculation */
if (tk->ntp_err_mult)
@@ -1690,13 +1693,33 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,
/* preserve the direction of correction */
negative = (tick_error < 0);
- /* Sort out the magnitude of the correction */
+ /* If any adjustment would pass the max, just return */
+ if (negative && (cur_adj - 1) <= (base - max))
+ return;
+ if (!negative && (cur_adj + 1) >= (base + max))
+ return;
+ /*
+ * Sort out the magnitude of the correction, but
+ * avoid making so large a correction that we go
+ * over the max adjustment.
+ */
+ adj_scale = 0;
tick_error = abs(tick_error);
- for (adj = 0; tick_error > interval; adj++)
+ while (tick_error > interval) {
+ u32 adj = 1 << (adj_scale + 1);
+
+ /* Check if adjustment gets us within 1 unit from the max */
+ if (negative && (cur_adj - adj) <= (base - max))
+ break;
+ if (!negative && (cur_adj + adj) >= (base + max))
+ break;
+
+ adj_scale++;
tick_error >>= 1;
+ }
/* scale the corrections */
- timekeeping_apply_adjustment(tk, offset, negative, adj);
+ timekeeping_apply_adjustment(tk, offset, negative, adj_scale);
}
/*