Loading drivers/bus/mhi/core/mhi_init.c +80 −79 Original line number Diff line number Diff line Loading @@ -403,72 +403,113 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl) return ret; } static int mhi_get_tsync_er_cfg(struct mhi_controller *mhi_cntrl) { int i; struct mhi_event *mhi_event = mhi_cntrl->mhi_event; /* find event ring with timesync support */ for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) if (mhi_event->data_type == MHI_ER_TSYNC_ELEMENT_TYPE) return mhi_event->er_index; return -ENOENT; } int mhi_init_timesync(struct mhi_controller *mhi_cntrl) { struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; struct mhi_timesync *mhi_tsync; u32 time_offset, db_offset; int ret; reinit_completion(&mhi_tsync->completion); read_lock_bh(&mhi_cntrl->pm_lock); if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { MHI_ERR("MHI host is not in active state\n"); read_unlock_bh(&mhi_cntrl->pm_lock); return -EIO; } mhi_cntrl->wake_get(mhi_cntrl, false); read_unlock_bh(&mhi_cntrl->pm_lock); mhi_cntrl->runtime_get(mhi_cntrl, mhi_cntrl->priv_data); mhi_cntrl->runtime_put(mhi_cntrl, mhi_cntrl->priv_data); if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { ret = -EIO; goto exit_timesync; } ret = mhi_send_cmd(mhi_cntrl, NULL, MHI_CMD_TIMSYNC_CFG); ret = mhi_get_capability_offset(mhi_cntrl, TIMESYNC_CAP_ID, &time_offset); if (ret) { MHI_ERR("Failed to send time sync cfg cmd\n"); goto error_send_cmd; MHI_LOG("No timesync capability found\n"); goto exit_timesync; } ret = wait_for_completion_timeout(&mhi_tsync->completion, msecs_to_jiffies(mhi_cntrl->timeout_ms)); read_unlock_bh(&mhi_cntrl->pm_lock); if (!ret || mhi_tsync->ccs != MHI_EV_CC_SUCCESS) { MHI_ERR("Failed to receive cmd completion for time_sync_cfg\n"); ret = -EIO; goto error_send_cmd; if (!mhi_cntrl->time_get || !mhi_cntrl->lpm_disable || !mhi_cntrl->lpm_enable) return -EINVAL; /* register method supported */ mhi_tsync = kzalloc(sizeof(*mhi_tsync), GFP_KERNEL); if (!mhi_tsync) return -ENOMEM; spin_lock_init(&mhi_tsync->lock); INIT_LIST_HEAD(&mhi_tsync->head); init_completion(&mhi_tsync->completion); /* save time_offset for obtaining time */ MHI_LOG("TIME OFFS:0x%x\n", time_offset); mhi_tsync->time_reg = mhi_cntrl->regs + time_offset + TIMESYNC_TIME_LOW_OFFSET; mhi_cntrl->mhi_tsync = mhi_tsync; ret = mhi_create_timesync_sysfs(mhi_cntrl); if (unlikely(ret)) { /* kernel method still work */ MHI_ERR("Failed to create timesync sysfs nodes\n"); } read_lock_bh(&mhi_cntrl->pm_lock); mhi_cntrl->wake_put(mhi_cntrl, false); if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { ret = -EIO; if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) goto error_sync_cap; ret = mhi_get_capability_offset(mhi_cntrl, TIMESYNC_CAP_ID, &time_offset); if (ret) { MHI_ERR("could not find timesync capability\n"); goto error_sync_cap; goto exit_timesync; } /* get DB offset if supported, else return */ ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, time_offset + TIMESYNC_DB_OFFSET, &db_offset); if (ret) goto error_sync_cap; if (ret || !db_offset) { ret = 0; goto exit_timesync; } MHI_LOG("TIMESYNC_DB OFFS:0x%x\n", db_offset); mhi_tsync->db = mhi_cntrl->regs + db_offset; error_sync_cap: read_unlock_bh(&mhi_cntrl->pm_lock); /* get time-sync event ring configuration */ ret = mhi_get_tsync_er_cfg(mhi_cntrl); if (ret < 0) { MHI_LOG("Could not find timesync event ring\n"); return ret; } error_send_cmd: read_lock_bh(&mhi_cntrl->pm_lock); mhi_cntrl->wake_put(mhi_cntrl, false); mhi_tsync->er_index = ret; ret = mhi_send_cmd(mhi_cntrl, NULL, MHI_CMD_TIMSYNC_CFG); if (ret) { MHI_ERR("Failed to send time sync cfg cmd\n"); return ret; } ret = wait_for_completion_timeout(&mhi_tsync->completion, msecs_to_jiffies(mhi_cntrl->timeout_ms)); if (!ret || mhi_tsync->ccs != MHI_EV_CC_SUCCESS) { MHI_ERR("Failed to get time cfg cmd completion\n"); return -EIO; } return 0; exit_timesync: read_unlock_bh(&mhi_cntrl->pm_lock); return ret; Loading Loading @@ -978,7 +1019,6 @@ static int of_parse_dt(struct mhi_controller *mhi_cntrl, struct device_node *of_node) { int ret; struct mhi_timesync *mhi_tsync; /* parse MHI channel configuration */ ret = of_parse_ch_cfg(mhi_cntrl, of_node); Loading @@ -995,28 +1035,6 @@ static int of_parse_dt(struct mhi_controller *mhi_cntrl, if (ret) mhi_cntrl->timeout_ms = MHI_TIMEOUT_MS; mhi_cntrl->time_sync = of_property_read_bool(of_node, "mhi,time-sync"); if (mhi_cntrl->time_sync) { mhi_tsync = kzalloc(sizeof(*mhi_tsync), GFP_KERNEL); if (!mhi_tsync) { ret = -ENOMEM; goto error_time_sync; } ret = of_property_read_u32(of_node, "mhi,tsync-er", &mhi_tsync->er_index); if (ret) goto error_time_sync; if (mhi_tsync->er_index >= mhi_cntrl->total_ev_rings) { ret = -EINVAL; goto error_time_sync; } mhi_cntrl->mhi_tsync = mhi_tsync; } mhi_cntrl->bounce_buf = of_property_read_bool(of_node, "mhi,use-bb"); ret = of_property_read_u32(of_node, "mhi,buffer-len", (u32 *)&mhi_cntrl->buffer_len); Loading @@ -1025,10 +1043,6 @@ static int of_parse_dt(struct mhi_controller *mhi_cntrl, return 0; error_time_sync: kfree(mhi_tsync); kfree(mhi_cntrl->mhi_event); error_ev_cfg: kfree(mhi_cntrl->mhi_chan); Loading Loading @@ -1057,11 +1071,6 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) if (ret) return -EINVAL; if (mhi_cntrl->time_sync && (!mhi_cntrl->time_get || !mhi_cntrl->lpm_disable || !mhi_cntrl->lpm_enable)) return -EINVAL; mhi_cntrl->mhi_cmd = kcalloc(NR_OF_CMD_RINGS, sizeof(*mhi_cntrl->mhi_cmd), GFP_KERNEL); if (!mhi_cntrl->mhi_cmd) { Loading Loading @@ -1105,14 +1114,6 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) rwlock_init(&mhi_chan->lock); } if (mhi_cntrl->mhi_tsync) { struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; spin_lock_init(&mhi_tsync->lock); INIT_LIST_HEAD(&mhi_tsync->head); init_completion(&mhi_tsync->completion); } if (mhi_cntrl->bounce_buf) { mhi_cntrl->map_single = mhi_map_single_use_bb; mhi_cntrl->unmap_single = mhi_unmap_single_use_bb; Loading drivers/bus/mhi/core/mhi_internal.h +11 −4 Original line number Diff line number Diff line Loading @@ -143,9 +143,9 @@ extern struct bus_type mhi_bus_type; #define TIMESYNC_CFG_NEXT_OFF_SHIFT (CAP_NEXT_CAP_SHIFT) #define TIMESYNC_CFG_NUMCMD_MASK (0xFF) #define TIMESYNC_CFG_NUMCMD_SHIFT (0) #define TIMESYNC_TIME_LOW_OFFSET (0x4) #define TIMESYNC_TIME_HIGH_OFFSET (0x8) #define TIMESYNC_DB_OFFSET (0xC) #define TIMESYNC_DB_OFFSET (0x4) #define TIMESYNC_TIME_LOW_OFFSET (0x8) #define TIMESYNC_TIME_HIGH_OFFSET (0xC) #define TIMESYNC_CAP_ID (2) Loading Loading @@ -211,6 +211,9 @@ extern struct bus_type mhi_bus_type; #define BHIE_RXVECSTATUS_STATUS_XFER_COMPL (0x02) #define BHIE_RXVECSTATUS_STATUS_ERROR (0x03) /* convert ticks to micro seconds by dividing by 19.2 */ #define TIME_TICKS_TO_US(x) (((x) * 10) / 192) struct mhi_event_ctxt { u32 reserved : 8; u32 intmodc : 8; Loading Loading @@ -614,9 +617,11 @@ struct tsync_node { struct mhi_timesync { u32 er_index; void __iomem *db; void __iomem *time_reg; enum MHI_EV_CCS ccs; struct completion completion; spinlock_t lock; spinlock_t lock; /* list protection */ struct mutex lpm_mutex; /* lpm protection */ struct list_head head; }; Loading Loading @@ -707,6 +712,8 @@ void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, int mhi_get_capability_offset(struct mhi_controller *mhi_cntrl, u32 capability, u32 *offset); int mhi_init_timesync(struct mhi_controller *mhi_cntrl); int mhi_create_timesync_sysfs(struct mhi_controller *mhi_cntrl); void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl); /* memory allocation methods */ static inline void *mhi_alloc_coherent(struct mhi_controller *mhi_cntrl, Loading drivers/bus/mhi/core/mhi_main.c +122 −4 Original line number Diff line number Diff line Loading @@ -595,15 +595,77 @@ static void mhi_assign_of_node(struct mhi_controller *mhi_cntrl, } } static ssize_t time_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mhi_device *mhi_dev = to_mhi_device(dev); struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; u64 t_host, t_device; int ret; ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device); if (ret) { MHI_ERR("Failed to obtain time, ret:%d\n", ret); return ret; } return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (ticks)\n", t_host, t_device); } static DEVICE_ATTR_RO(time); static ssize_t time_us_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mhi_device *mhi_dev = to_mhi_device(dev); struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; u64 t_host, t_device; int ret; ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device); if (ret) { MHI_ERR("Failed to obtain time, ret:%d\n", ret); return ret; } return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (us)\n", TIME_TICKS_TO_US(t_host), TIME_TICKS_TO_US(t_device)); } static DEVICE_ATTR_RO(time_us); static struct attribute *mhi_tsync_attrs[] = { &dev_attr_time.attr, &dev_attr_time_us.attr, NULL, }; static const struct attribute_group mhi_tsync_group = { .attrs = mhi_tsync_attrs, }; void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl) { if (mhi_cntrl->mhi_tsync) { sysfs_remove_group(&mhi_cntrl->mhi_dev->dev.kobj, &mhi_tsync_group); kfree(mhi_cntrl->mhi_tsync); mhi_cntrl->mhi_tsync = NULL; } } int mhi_create_timesync_sysfs(struct mhi_controller *mhi_cntrl) { return sysfs_create_group(&mhi_cntrl->mhi_dev->dev.kobj, &mhi_tsync_group); } static void mhi_create_time_sync_dev(struct mhi_controller *mhi_cntrl) { struct mhi_device *mhi_dev; struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; int ret; if (!mhi_tsync || !mhi_tsync->db) return; if (!MHI_IN_MISSION_MODE(mhi_cntrl->ee)) return; Loading Loading @@ -1779,6 +1841,62 @@ int mhi_poll(struct mhi_device *mhi_dev, } EXPORT_SYMBOL(mhi_poll); int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, u64 *t_host, u64 *t_dev) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; int ret; /* not all devices support time feature */ if (!mhi_tsync) return -EIO; /* bring to M0 state */ ret = __mhi_device_get_sync(mhi_cntrl); if (ret) return ret; mutex_lock(&mhi_tsync->lpm_mutex); read_lock_bh(&mhi_cntrl->pm_lock); if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) { MHI_ERR("MHI is not in active state, pm_state:%s\n", to_mhi_pm_state_str(mhi_cntrl->pm_state)); ret = -EIO; goto error_invalid_state; } /* disable link level low power modes */ ret = mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data); if (ret) goto error_invalid_state; /* * time critical code to fetch device times, * delay between these two steps should be * deterministic as possible. */ preempt_disable(); local_irq_disable(); *t_host = mhi_cntrl->time_get(mhi_cntrl, mhi_cntrl->priv_data); *t_dev = readq_relaxed_no_log(mhi_tsync->time_reg); local_irq_enable(); preempt_enable(); mhi_cntrl->lpm_enable(mhi_cntrl, mhi_cntrl->priv_data); error_invalid_state: mhi_cntrl->wake_put(mhi_cntrl, false); read_unlock_bh(&mhi_cntrl->pm_lock); mutex_unlock(&mhi_tsync->lpm_mutex); return ret; } EXPORT_SYMBOL(mhi_get_remote_time_sync); /** * mhi_get_remote_time - Get external modem time relative to host time Loading drivers/bus/mhi/core/mhi_pm.c +4 −5 Original line number Diff line number Diff line Loading @@ -462,7 +462,6 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) read_unlock_bh(&mhi_cntrl->pm_lock); /* setup support for time sync */ if (mhi_cntrl->time_sync) mhi_init_timesync(mhi_cntrl); MHI_LOG("Adding new devices\n"); Loading Loading @@ -601,6 +600,9 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl, er_ctxt->wp = er_ctxt->rbase; } /* remove support for time sync */ mhi_destroy_timesync(mhi_cntrl); if (cur_state == MHI_PM_SYS_ERR_PROCESS) { mhi_ready_state_transition(mhi_cntrl); } else { Loading Loading @@ -867,9 +869,6 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful) mhi_deinit_free_irq(mhi_cntrl); mhi_deinit_dev_ctxt(mhi_cntrl); } if (mhi_cntrl->mhi_tsync) mhi_cntrl->mhi_tsync->db = NULL; } EXPORT_SYMBOL(mhi_power_down); Loading include/linux/mhi.h +11 −1 Original line number Diff line number Diff line Loading @@ -267,7 +267,6 @@ struct mhi_controller { size_t buffer_len; /* supports time sync feature */ bool time_sync; struct mhi_timesync *mhi_tsync; struct mhi_device *tsync_dev; Loading Loading @@ -595,6 +594,17 @@ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic); */ int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl); /** * mhi_get_remote_time_sync - Get external soc time relative to local soc time * using MMIO method. * @mhi_dev: Device associated with the channels * @t_host: Pointer to output local soc time * @t_dev: Pointer to output remote soc time */ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, u64 *t_host, u64 *t_dev); #ifndef CONFIG_ARCH_QCOM #ifdef CONFIG_MHI_DEBUG Loading Loading
drivers/bus/mhi/core/mhi_init.c +80 −79 Original line number Diff line number Diff line Loading @@ -403,72 +403,113 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl) return ret; } static int mhi_get_tsync_er_cfg(struct mhi_controller *mhi_cntrl) { int i; struct mhi_event *mhi_event = mhi_cntrl->mhi_event; /* find event ring with timesync support */ for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) if (mhi_event->data_type == MHI_ER_TSYNC_ELEMENT_TYPE) return mhi_event->er_index; return -ENOENT; } int mhi_init_timesync(struct mhi_controller *mhi_cntrl) { struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; struct mhi_timesync *mhi_tsync; u32 time_offset, db_offset; int ret; reinit_completion(&mhi_tsync->completion); read_lock_bh(&mhi_cntrl->pm_lock); if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { MHI_ERR("MHI host is not in active state\n"); read_unlock_bh(&mhi_cntrl->pm_lock); return -EIO; } mhi_cntrl->wake_get(mhi_cntrl, false); read_unlock_bh(&mhi_cntrl->pm_lock); mhi_cntrl->runtime_get(mhi_cntrl, mhi_cntrl->priv_data); mhi_cntrl->runtime_put(mhi_cntrl, mhi_cntrl->priv_data); if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { ret = -EIO; goto exit_timesync; } ret = mhi_send_cmd(mhi_cntrl, NULL, MHI_CMD_TIMSYNC_CFG); ret = mhi_get_capability_offset(mhi_cntrl, TIMESYNC_CAP_ID, &time_offset); if (ret) { MHI_ERR("Failed to send time sync cfg cmd\n"); goto error_send_cmd; MHI_LOG("No timesync capability found\n"); goto exit_timesync; } ret = wait_for_completion_timeout(&mhi_tsync->completion, msecs_to_jiffies(mhi_cntrl->timeout_ms)); read_unlock_bh(&mhi_cntrl->pm_lock); if (!ret || mhi_tsync->ccs != MHI_EV_CC_SUCCESS) { MHI_ERR("Failed to receive cmd completion for time_sync_cfg\n"); ret = -EIO; goto error_send_cmd; if (!mhi_cntrl->time_get || !mhi_cntrl->lpm_disable || !mhi_cntrl->lpm_enable) return -EINVAL; /* register method supported */ mhi_tsync = kzalloc(sizeof(*mhi_tsync), GFP_KERNEL); if (!mhi_tsync) return -ENOMEM; spin_lock_init(&mhi_tsync->lock); INIT_LIST_HEAD(&mhi_tsync->head); init_completion(&mhi_tsync->completion); /* save time_offset for obtaining time */ MHI_LOG("TIME OFFS:0x%x\n", time_offset); mhi_tsync->time_reg = mhi_cntrl->regs + time_offset + TIMESYNC_TIME_LOW_OFFSET; mhi_cntrl->mhi_tsync = mhi_tsync; ret = mhi_create_timesync_sysfs(mhi_cntrl); if (unlikely(ret)) { /* kernel method still work */ MHI_ERR("Failed to create timesync sysfs nodes\n"); } read_lock_bh(&mhi_cntrl->pm_lock); mhi_cntrl->wake_put(mhi_cntrl, false); if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { ret = -EIO; if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) goto error_sync_cap; ret = mhi_get_capability_offset(mhi_cntrl, TIMESYNC_CAP_ID, &time_offset); if (ret) { MHI_ERR("could not find timesync capability\n"); goto error_sync_cap; goto exit_timesync; } /* get DB offset if supported, else return */ ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, time_offset + TIMESYNC_DB_OFFSET, &db_offset); if (ret) goto error_sync_cap; if (ret || !db_offset) { ret = 0; goto exit_timesync; } MHI_LOG("TIMESYNC_DB OFFS:0x%x\n", db_offset); mhi_tsync->db = mhi_cntrl->regs + db_offset; error_sync_cap: read_unlock_bh(&mhi_cntrl->pm_lock); /* get time-sync event ring configuration */ ret = mhi_get_tsync_er_cfg(mhi_cntrl); if (ret < 0) { MHI_LOG("Could not find timesync event ring\n"); return ret; } error_send_cmd: read_lock_bh(&mhi_cntrl->pm_lock); mhi_cntrl->wake_put(mhi_cntrl, false); mhi_tsync->er_index = ret; ret = mhi_send_cmd(mhi_cntrl, NULL, MHI_CMD_TIMSYNC_CFG); if (ret) { MHI_ERR("Failed to send time sync cfg cmd\n"); return ret; } ret = wait_for_completion_timeout(&mhi_tsync->completion, msecs_to_jiffies(mhi_cntrl->timeout_ms)); if (!ret || mhi_tsync->ccs != MHI_EV_CC_SUCCESS) { MHI_ERR("Failed to get time cfg cmd completion\n"); return -EIO; } return 0; exit_timesync: read_unlock_bh(&mhi_cntrl->pm_lock); return ret; Loading Loading @@ -978,7 +1019,6 @@ static int of_parse_dt(struct mhi_controller *mhi_cntrl, struct device_node *of_node) { int ret; struct mhi_timesync *mhi_tsync; /* parse MHI channel configuration */ ret = of_parse_ch_cfg(mhi_cntrl, of_node); Loading @@ -995,28 +1035,6 @@ static int of_parse_dt(struct mhi_controller *mhi_cntrl, if (ret) mhi_cntrl->timeout_ms = MHI_TIMEOUT_MS; mhi_cntrl->time_sync = of_property_read_bool(of_node, "mhi,time-sync"); if (mhi_cntrl->time_sync) { mhi_tsync = kzalloc(sizeof(*mhi_tsync), GFP_KERNEL); if (!mhi_tsync) { ret = -ENOMEM; goto error_time_sync; } ret = of_property_read_u32(of_node, "mhi,tsync-er", &mhi_tsync->er_index); if (ret) goto error_time_sync; if (mhi_tsync->er_index >= mhi_cntrl->total_ev_rings) { ret = -EINVAL; goto error_time_sync; } mhi_cntrl->mhi_tsync = mhi_tsync; } mhi_cntrl->bounce_buf = of_property_read_bool(of_node, "mhi,use-bb"); ret = of_property_read_u32(of_node, "mhi,buffer-len", (u32 *)&mhi_cntrl->buffer_len); Loading @@ -1025,10 +1043,6 @@ static int of_parse_dt(struct mhi_controller *mhi_cntrl, return 0; error_time_sync: kfree(mhi_tsync); kfree(mhi_cntrl->mhi_event); error_ev_cfg: kfree(mhi_cntrl->mhi_chan); Loading Loading @@ -1057,11 +1071,6 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) if (ret) return -EINVAL; if (mhi_cntrl->time_sync && (!mhi_cntrl->time_get || !mhi_cntrl->lpm_disable || !mhi_cntrl->lpm_enable)) return -EINVAL; mhi_cntrl->mhi_cmd = kcalloc(NR_OF_CMD_RINGS, sizeof(*mhi_cntrl->mhi_cmd), GFP_KERNEL); if (!mhi_cntrl->mhi_cmd) { Loading Loading @@ -1105,14 +1114,6 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) rwlock_init(&mhi_chan->lock); } if (mhi_cntrl->mhi_tsync) { struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; spin_lock_init(&mhi_tsync->lock); INIT_LIST_HEAD(&mhi_tsync->head); init_completion(&mhi_tsync->completion); } if (mhi_cntrl->bounce_buf) { mhi_cntrl->map_single = mhi_map_single_use_bb; mhi_cntrl->unmap_single = mhi_unmap_single_use_bb; Loading
drivers/bus/mhi/core/mhi_internal.h +11 −4 Original line number Diff line number Diff line Loading @@ -143,9 +143,9 @@ extern struct bus_type mhi_bus_type; #define TIMESYNC_CFG_NEXT_OFF_SHIFT (CAP_NEXT_CAP_SHIFT) #define TIMESYNC_CFG_NUMCMD_MASK (0xFF) #define TIMESYNC_CFG_NUMCMD_SHIFT (0) #define TIMESYNC_TIME_LOW_OFFSET (0x4) #define TIMESYNC_TIME_HIGH_OFFSET (0x8) #define TIMESYNC_DB_OFFSET (0xC) #define TIMESYNC_DB_OFFSET (0x4) #define TIMESYNC_TIME_LOW_OFFSET (0x8) #define TIMESYNC_TIME_HIGH_OFFSET (0xC) #define TIMESYNC_CAP_ID (2) Loading Loading @@ -211,6 +211,9 @@ extern struct bus_type mhi_bus_type; #define BHIE_RXVECSTATUS_STATUS_XFER_COMPL (0x02) #define BHIE_RXVECSTATUS_STATUS_ERROR (0x03) /* convert ticks to micro seconds by dividing by 19.2 */ #define TIME_TICKS_TO_US(x) (((x) * 10) / 192) struct mhi_event_ctxt { u32 reserved : 8; u32 intmodc : 8; Loading Loading @@ -614,9 +617,11 @@ struct tsync_node { struct mhi_timesync { u32 er_index; void __iomem *db; void __iomem *time_reg; enum MHI_EV_CCS ccs; struct completion completion; spinlock_t lock; spinlock_t lock; /* list protection */ struct mutex lpm_mutex; /* lpm protection */ struct list_head head; }; Loading Loading @@ -707,6 +712,8 @@ void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, int mhi_get_capability_offset(struct mhi_controller *mhi_cntrl, u32 capability, u32 *offset); int mhi_init_timesync(struct mhi_controller *mhi_cntrl); int mhi_create_timesync_sysfs(struct mhi_controller *mhi_cntrl); void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl); /* memory allocation methods */ static inline void *mhi_alloc_coherent(struct mhi_controller *mhi_cntrl, Loading
drivers/bus/mhi/core/mhi_main.c +122 −4 Original line number Diff line number Diff line Loading @@ -595,15 +595,77 @@ static void mhi_assign_of_node(struct mhi_controller *mhi_cntrl, } } static ssize_t time_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mhi_device *mhi_dev = to_mhi_device(dev); struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; u64 t_host, t_device; int ret; ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device); if (ret) { MHI_ERR("Failed to obtain time, ret:%d\n", ret); return ret; } return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (ticks)\n", t_host, t_device); } static DEVICE_ATTR_RO(time); static ssize_t time_us_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mhi_device *mhi_dev = to_mhi_device(dev); struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; u64 t_host, t_device; int ret; ret = mhi_get_remote_time_sync(mhi_dev, &t_host, &t_device); if (ret) { MHI_ERR("Failed to obtain time, ret:%d\n", ret); return ret; } return scnprintf(buf, PAGE_SIZE, "local: %llu remote: %llu (us)\n", TIME_TICKS_TO_US(t_host), TIME_TICKS_TO_US(t_device)); } static DEVICE_ATTR_RO(time_us); static struct attribute *mhi_tsync_attrs[] = { &dev_attr_time.attr, &dev_attr_time_us.attr, NULL, }; static const struct attribute_group mhi_tsync_group = { .attrs = mhi_tsync_attrs, }; void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl) { if (mhi_cntrl->mhi_tsync) { sysfs_remove_group(&mhi_cntrl->mhi_dev->dev.kobj, &mhi_tsync_group); kfree(mhi_cntrl->mhi_tsync); mhi_cntrl->mhi_tsync = NULL; } } int mhi_create_timesync_sysfs(struct mhi_controller *mhi_cntrl) { return sysfs_create_group(&mhi_cntrl->mhi_dev->dev.kobj, &mhi_tsync_group); } static void mhi_create_time_sync_dev(struct mhi_controller *mhi_cntrl) { struct mhi_device *mhi_dev; struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; int ret; if (!mhi_tsync || !mhi_tsync->db) return; if (!MHI_IN_MISSION_MODE(mhi_cntrl->ee)) return; Loading Loading @@ -1779,6 +1841,62 @@ int mhi_poll(struct mhi_device *mhi_dev, } EXPORT_SYMBOL(mhi_poll); int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, u64 *t_host, u64 *t_dev) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; int ret; /* not all devices support time feature */ if (!mhi_tsync) return -EIO; /* bring to M0 state */ ret = __mhi_device_get_sync(mhi_cntrl); if (ret) return ret; mutex_lock(&mhi_tsync->lpm_mutex); read_lock_bh(&mhi_cntrl->pm_lock); if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) { MHI_ERR("MHI is not in active state, pm_state:%s\n", to_mhi_pm_state_str(mhi_cntrl->pm_state)); ret = -EIO; goto error_invalid_state; } /* disable link level low power modes */ ret = mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data); if (ret) goto error_invalid_state; /* * time critical code to fetch device times, * delay between these two steps should be * deterministic as possible. */ preempt_disable(); local_irq_disable(); *t_host = mhi_cntrl->time_get(mhi_cntrl, mhi_cntrl->priv_data); *t_dev = readq_relaxed_no_log(mhi_tsync->time_reg); local_irq_enable(); preempt_enable(); mhi_cntrl->lpm_enable(mhi_cntrl, mhi_cntrl->priv_data); error_invalid_state: mhi_cntrl->wake_put(mhi_cntrl, false); read_unlock_bh(&mhi_cntrl->pm_lock); mutex_unlock(&mhi_tsync->lpm_mutex); return ret; } EXPORT_SYMBOL(mhi_get_remote_time_sync); /** * mhi_get_remote_time - Get external modem time relative to host time Loading
drivers/bus/mhi/core/mhi_pm.c +4 −5 Original line number Diff line number Diff line Loading @@ -462,7 +462,6 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) read_unlock_bh(&mhi_cntrl->pm_lock); /* setup support for time sync */ if (mhi_cntrl->time_sync) mhi_init_timesync(mhi_cntrl); MHI_LOG("Adding new devices\n"); Loading Loading @@ -601,6 +600,9 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl, er_ctxt->wp = er_ctxt->rbase; } /* remove support for time sync */ mhi_destroy_timesync(mhi_cntrl); if (cur_state == MHI_PM_SYS_ERR_PROCESS) { mhi_ready_state_transition(mhi_cntrl); } else { Loading Loading @@ -867,9 +869,6 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful) mhi_deinit_free_irq(mhi_cntrl); mhi_deinit_dev_ctxt(mhi_cntrl); } if (mhi_cntrl->mhi_tsync) mhi_cntrl->mhi_tsync->db = NULL; } EXPORT_SYMBOL(mhi_power_down); Loading
include/linux/mhi.h +11 −1 Original line number Diff line number Diff line Loading @@ -267,7 +267,6 @@ struct mhi_controller { size_t buffer_len; /* supports time sync feature */ bool time_sync; struct mhi_timesync *mhi_tsync; struct mhi_device *tsync_dev; Loading Loading @@ -595,6 +594,17 @@ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic); */ int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl); /** * mhi_get_remote_time_sync - Get external soc time relative to local soc time * using MMIO method. * @mhi_dev: Device associated with the channels * @t_host: Pointer to output local soc time * @t_dev: Pointer to output remote soc time */ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, u64 *t_host, u64 *t_dev); #ifndef CONFIG_ARCH_QCOM #ifdef CONFIG_MHI_DEBUG Loading