diff options
| -rw-r--r-- | arch/arm64/configs/msm-auto-perf_defconfig | 1 | ||||
| -rw-r--r-- | arch/arm64/configs/msm-auto_defconfig | 1 | ||||
| -rw-r--r-- | drivers/soc/qcom/hab/hab.c | 8 | ||||
| -rw-r--r-- | drivers/soc/qcom/hab/hab.h | 4 | ||||
| -rw-r--r-- | drivers/soc/qcom/hab/hab_msg.c | 16 | ||||
| -rw-r--r-- | drivers/soc/qcom/hab/qvm_comm.c | 12 | ||||
| -rw-r--r-- | include/linux/habmm.h | 31 | ||||
| -rw-r--r-- | kernel/time/timekeeping.c | 31 |
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); } /* |
