Loading drivers/platform/msm/mhi_dev/mhi.c +25 −26 Original line number Diff line number Diff line Loading @@ -940,8 +940,6 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, struct mhi_addr host_addr; struct mhi_dev_channel *ch; struct mhi_dev_ring *ring; char *connected[2] = { "MHI_CHANNEL_STATE_12=CONNECTED", NULL}; char *disconnected[2] = { "MHI_CHANNEL_STATE_12=DISCONNECTED", NULL}; ch_id = el->generic.chid; mhi_log(MHI_MSG_VERBOSE, "for channel:%d and cmd:%d\n", Loading Loading @@ -1027,9 +1025,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, mhi_update_state_info(ch_id, MHI_STATE_CONNECTED); /* Trigger callback to clients */ mhi_dev_trigger_cb(ch_id); if (ch_id == MHI_CLIENT_MBIM_OUT) kobject_uevent_env(&mhi_ctx->dev->kobj, KOBJ_CHANGE, connected); mhi_uci_chan_state_notify(mhi, ch_id, MHI_STATE_CONNECTED); break; case MHI_DEV_RING_EL_STOP: if (ch_id >= HW_CHANNEL_BASE) { Loading Loading @@ -1083,9 +1079,10 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, mutex_unlock(&ch->ch_lock); mhi_update_state_info(ch_id, MHI_STATE_DISCONNECTED); if (ch_id == MHI_CLIENT_MBIM_OUT) kobject_uevent_env(&mhi_ctx->dev->kobj, KOBJ_CHANGE, disconnected); /* Trigger callback to clients */ mhi_dev_trigger_cb(ch_id); mhi_uci_chan_state_notify(mhi, ch_id, MHI_STATE_DISCONNECTED); } break; case MHI_DEV_RING_EL_RESET: Loading Loading @@ -1159,9 +1156,9 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, pr_err("Error sending command completion event\n"); mutex_unlock(&ch->ch_lock); mhi_update_state_info(ch_id, MHI_STATE_DISCONNECTED); if (ch_id == MHI_CLIENT_MBIM_OUT) kobject_uevent_env(&mhi_ctx->dev->kobj, KOBJ_CHANGE, disconnected); mhi_dev_trigger_cb(ch_id); mhi_uci_chan_state_notify(mhi, ch_id, MHI_STATE_DISCONNECTED); } break; default: Loading Loading @@ -1324,13 +1321,25 @@ static void mhi_dev_check_channel_interrupt(struct mhi_dev *mhi) } } static void mhi_update_state_info_all(enum mhi_ctrl_info info) { int i; struct mhi_dev_client_cb_reason reason; mhi_ctx->ctrl_info = info; for (i = 0; i < MHI_MAX_CHANNELS; ++i) channel_state_info[i].ctrl_info = info; /* For legacy reasons for QTI client */ reason.reason = MHI_DEV_CTRL_UPDATE; uci_ctrl_update(&reason); } static int mhi_dev_abort(struct mhi_dev *mhi) { struct mhi_dev_channel *ch; struct mhi_dev_ring *ring; int ch_id = 0, rc = 0; char *disconnected_12[2] = { "MHI_CHANNEL_STATE_12=DISCONNECTED", NULL}; char *disconnected_14[2] = { "MHI_CHANNEL_STATE_14=DISCONNECTED", NULL}; /* Hard stop all the channels */ for (ch_id = 0; ch_id < mhi->cfg.channels; ch_id++) { Loading @@ -1344,19 +1353,9 @@ static int mhi_dev_abort(struct mhi_dev *mhi) mutex_unlock(&ch->ch_lock); } /* Update ctrl node */ mhi_update_state_info(MHI_DEV_UEVENT_CTRL, MHI_STATE_DISCONNECTED); mhi_update_state_info(MHI_CLIENT_MBIM_OUT, MHI_STATE_DISCONNECTED); mhi_update_state_info(MHI_CLIENT_QMI_OUT, MHI_STATE_DISCONNECTED); rc = kobject_uevent_env(&mhi_ctx->dev->kobj, KOBJ_CHANGE, disconnected_12); if (rc) pr_err("Error sending uevent:%d\n", rc); rc = kobject_uevent_env(&mhi_ctx->dev->kobj, KOBJ_CHANGE, disconnected_14); if (rc) pr_err("Error sending uevent:%d\n", rc); /* Update channel state and notify clients */ mhi_update_state_info_all(MHI_STATE_DISCONNECTED); mhi_uci_chan_state_notify_all(mhi, MHI_STATE_DISCONNECTED); flush_workqueue(mhi->ring_init_wq); flush_workqueue(mhi->pending_ring_wq); Loading drivers/platform/msm/mhi_dev/mhi.h +12 −0 Original line number Diff line number Diff line Loading @@ -1095,5 +1095,17 @@ int mhi_dev_net_interface_init(void); void mhi_dev_notify_a7_event(struct mhi_dev *mhi); void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason); /** * mhi_uci_chan_state_notify_all - Notifies channel state updates for * all clients who have uevents enabled. */ void mhi_uci_chan_state_notify_all(struct mhi_dev *mhi, enum mhi_ctrl_info ch_state); /** * mhi_uci_chan_state_notify - Notifies channel state update to the client * if uevents are enabled. */ void mhi_uci_chan_state_notify(struct mhi_dev *mhi, enum mhi_client_channel ch_id, enum mhi_ctrl_info ch_state); #endif /* _MHI_H */ drivers/platform/msm/mhi_dev/mhi_uci.c +75 −2 Original line number Diff line number Diff line Loading @@ -83,6 +83,8 @@ struct chan_attr { void (*tre_notif_cb)(struct mhi_dev_client_cb_reason *reason); /* Write completion - false if not needed */ bool wr_cmpl; /* Uevent broadcast of channel state */ bool state_bcast; }; Loading Loading @@ -146,7 +148,10 @@ static const struct chan_attr uci_chan_attr_table[] = { MAX_NR_TRBS_PER_CHAN, MHI_DIR_OUT, NULL, NULL NULL, NULL, false, true }, { MHI_CLIENT_MBIM_IN, Loading @@ -162,7 +167,10 @@ static const struct chan_attr uci_chan_attr_table[] = { MAX_NR_TRBS_PER_CHAN, MHI_DIR_OUT, NULL, NULL NULL, NULL, false, true }, { MHI_CLIENT_QMI_IN, Loading Loading @@ -1143,6 +1151,71 @@ static ssize_t mhi_uci_client_write(struct file *file, } void mhi_uci_chan_state_notify_all(struct mhi_dev *mhi, enum mhi_ctrl_info ch_state) { unsigned int i; const struct chan_attr *chan_attrib; for (i = 0; i < ARRAY_SIZE(uci_chan_attr_table); i++) { chan_attrib = &uci_chan_attr_table[i]; if (chan_attrib->state_bcast) { uci_log(UCI_DBG_ERROR, "Calling notify for ch %d\n", chan_attrib->chan_id); mhi_uci_chan_state_notify(mhi, chan_attrib->chan_id, ch_state); } } } EXPORT_SYMBOL(mhi_uci_chan_state_notify_all); void mhi_uci_chan_state_notify(struct mhi_dev *mhi, enum mhi_client_channel ch_id, enum mhi_ctrl_info ch_state) { struct uci_client *uci_handle; char *buf[2]; int rc; if (ch_id < 0 || ch_id >= MHI_MAX_SOFTWARE_CHANNELS) { uci_log(UCI_DBG_ERROR, "Invalid chan %d\n", ch_id); return; } uci_handle = &uci_ctxt.client_handles[CHAN_TO_CLIENT(ch_id)]; if (!uci_handle->in_chan_attr || !uci_handle->in_chan_attr->state_bcast) { uci_log(UCI_DBG_VERBOSE, "Uevents not enabled for chan %d\n", ch_id); return; } if (ch_state == MHI_STATE_CONNECTED) { buf[0] = kasprintf(GFP_KERNEL, "MHI_CHANNEL_STATE_%d=CONNECTED", ch_id); buf[1] = NULL; } else if (ch_state == MHI_STATE_DISCONNECTED) { buf[0] = kasprintf(GFP_KERNEL, "MHI_CHANNEL_STATE_%d=DISCONNECTED", ch_id); buf[1] = NULL; } else { uci_log(UCI_DBG_ERROR, "Unsupported chan state %d\n", ch_state); return; } if (!buf[0]) { uci_log(UCI_DBG_ERROR, "kasprintf failed for uevent buf!\n"); return; } rc = kobject_uevent_env(&mhi->dev->kobj, KOBJ_CHANGE, buf); if (rc) uci_log(UCI_DBG_ERROR, "Sending uevent failed for chan %d\n", ch_id); kfree(buf[0]); } EXPORT_SYMBOL(mhi_uci_chan_state_notify); void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason) { struct uci_ctrl *uci_ctrl_handle = NULL; Loading Loading
drivers/platform/msm/mhi_dev/mhi.c +25 −26 Original line number Diff line number Diff line Loading @@ -940,8 +940,6 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, struct mhi_addr host_addr; struct mhi_dev_channel *ch; struct mhi_dev_ring *ring; char *connected[2] = { "MHI_CHANNEL_STATE_12=CONNECTED", NULL}; char *disconnected[2] = { "MHI_CHANNEL_STATE_12=DISCONNECTED", NULL}; ch_id = el->generic.chid; mhi_log(MHI_MSG_VERBOSE, "for channel:%d and cmd:%d\n", Loading Loading @@ -1027,9 +1025,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, mhi_update_state_info(ch_id, MHI_STATE_CONNECTED); /* Trigger callback to clients */ mhi_dev_trigger_cb(ch_id); if (ch_id == MHI_CLIENT_MBIM_OUT) kobject_uevent_env(&mhi_ctx->dev->kobj, KOBJ_CHANGE, connected); mhi_uci_chan_state_notify(mhi, ch_id, MHI_STATE_CONNECTED); break; case MHI_DEV_RING_EL_STOP: if (ch_id >= HW_CHANNEL_BASE) { Loading Loading @@ -1083,9 +1079,10 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, mutex_unlock(&ch->ch_lock); mhi_update_state_info(ch_id, MHI_STATE_DISCONNECTED); if (ch_id == MHI_CLIENT_MBIM_OUT) kobject_uevent_env(&mhi_ctx->dev->kobj, KOBJ_CHANGE, disconnected); /* Trigger callback to clients */ mhi_dev_trigger_cb(ch_id); mhi_uci_chan_state_notify(mhi, ch_id, MHI_STATE_DISCONNECTED); } break; case MHI_DEV_RING_EL_RESET: Loading Loading @@ -1159,9 +1156,9 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, pr_err("Error sending command completion event\n"); mutex_unlock(&ch->ch_lock); mhi_update_state_info(ch_id, MHI_STATE_DISCONNECTED); if (ch_id == MHI_CLIENT_MBIM_OUT) kobject_uevent_env(&mhi_ctx->dev->kobj, KOBJ_CHANGE, disconnected); mhi_dev_trigger_cb(ch_id); mhi_uci_chan_state_notify(mhi, ch_id, MHI_STATE_DISCONNECTED); } break; default: Loading Loading @@ -1324,13 +1321,25 @@ static void mhi_dev_check_channel_interrupt(struct mhi_dev *mhi) } } static void mhi_update_state_info_all(enum mhi_ctrl_info info) { int i; struct mhi_dev_client_cb_reason reason; mhi_ctx->ctrl_info = info; for (i = 0; i < MHI_MAX_CHANNELS; ++i) channel_state_info[i].ctrl_info = info; /* For legacy reasons for QTI client */ reason.reason = MHI_DEV_CTRL_UPDATE; uci_ctrl_update(&reason); } static int mhi_dev_abort(struct mhi_dev *mhi) { struct mhi_dev_channel *ch; struct mhi_dev_ring *ring; int ch_id = 0, rc = 0; char *disconnected_12[2] = { "MHI_CHANNEL_STATE_12=DISCONNECTED", NULL}; char *disconnected_14[2] = { "MHI_CHANNEL_STATE_14=DISCONNECTED", NULL}; /* Hard stop all the channels */ for (ch_id = 0; ch_id < mhi->cfg.channels; ch_id++) { Loading @@ -1344,19 +1353,9 @@ static int mhi_dev_abort(struct mhi_dev *mhi) mutex_unlock(&ch->ch_lock); } /* Update ctrl node */ mhi_update_state_info(MHI_DEV_UEVENT_CTRL, MHI_STATE_DISCONNECTED); mhi_update_state_info(MHI_CLIENT_MBIM_OUT, MHI_STATE_DISCONNECTED); mhi_update_state_info(MHI_CLIENT_QMI_OUT, MHI_STATE_DISCONNECTED); rc = kobject_uevent_env(&mhi_ctx->dev->kobj, KOBJ_CHANGE, disconnected_12); if (rc) pr_err("Error sending uevent:%d\n", rc); rc = kobject_uevent_env(&mhi_ctx->dev->kobj, KOBJ_CHANGE, disconnected_14); if (rc) pr_err("Error sending uevent:%d\n", rc); /* Update channel state and notify clients */ mhi_update_state_info_all(MHI_STATE_DISCONNECTED); mhi_uci_chan_state_notify_all(mhi, MHI_STATE_DISCONNECTED); flush_workqueue(mhi->ring_init_wq); flush_workqueue(mhi->pending_ring_wq); Loading
drivers/platform/msm/mhi_dev/mhi.h +12 −0 Original line number Diff line number Diff line Loading @@ -1095,5 +1095,17 @@ int mhi_dev_net_interface_init(void); void mhi_dev_notify_a7_event(struct mhi_dev *mhi); void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason); /** * mhi_uci_chan_state_notify_all - Notifies channel state updates for * all clients who have uevents enabled. */ void mhi_uci_chan_state_notify_all(struct mhi_dev *mhi, enum mhi_ctrl_info ch_state); /** * mhi_uci_chan_state_notify - Notifies channel state update to the client * if uevents are enabled. */ void mhi_uci_chan_state_notify(struct mhi_dev *mhi, enum mhi_client_channel ch_id, enum mhi_ctrl_info ch_state); #endif /* _MHI_H */
drivers/platform/msm/mhi_dev/mhi_uci.c +75 −2 Original line number Diff line number Diff line Loading @@ -83,6 +83,8 @@ struct chan_attr { void (*tre_notif_cb)(struct mhi_dev_client_cb_reason *reason); /* Write completion - false if not needed */ bool wr_cmpl; /* Uevent broadcast of channel state */ bool state_bcast; }; Loading Loading @@ -146,7 +148,10 @@ static const struct chan_attr uci_chan_attr_table[] = { MAX_NR_TRBS_PER_CHAN, MHI_DIR_OUT, NULL, NULL NULL, NULL, false, true }, { MHI_CLIENT_MBIM_IN, Loading @@ -162,7 +167,10 @@ static const struct chan_attr uci_chan_attr_table[] = { MAX_NR_TRBS_PER_CHAN, MHI_DIR_OUT, NULL, NULL NULL, NULL, false, true }, { MHI_CLIENT_QMI_IN, Loading Loading @@ -1143,6 +1151,71 @@ static ssize_t mhi_uci_client_write(struct file *file, } void mhi_uci_chan_state_notify_all(struct mhi_dev *mhi, enum mhi_ctrl_info ch_state) { unsigned int i; const struct chan_attr *chan_attrib; for (i = 0; i < ARRAY_SIZE(uci_chan_attr_table); i++) { chan_attrib = &uci_chan_attr_table[i]; if (chan_attrib->state_bcast) { uci_log(UCI_DBG_ERROR, "Calling notify for ch %d\n", chan_attrib->chan_id); mhi_uci_chan_state_notify(mhi, chan_attrib->chan_id, ch_state); } } } EXPORT_SYMBOL(mhi_uci_chan_state_notify_all); void mhi_uci_chan_state_notify(struct mhi_dev *mhi, enum mhi_client_channel ch_id, enum mhi_ctrl_info ch_state) { struct uci_client *uci_handle; char *buf[2]; int rc; if (ch_id < 0 || ch_id >= MHI_MAX_SOFTWARE_CHANNELS) { uci_log(UCI_DBG_ERROR, "Invalid chan %d\n", ch_id); return; } uci_handle = &uci_ctxt.client_handles[CHAN_TO_CLIENT(ch_id)]; if (!uci_handle->in_chan_attr || !uci_handle->in_chan_attr->state_bcast) { uci_log(UCI_DBG_VERBOSE, "Uevents not enabled for chan %d\n", ch_id); return; } if (ch_state == MHI_STATE_CONNECTED) { buf[0] = kasprintf(GFP_KERNEL, "MHI_CHANNEL_STATE_%d=CONNECTED", ch_id); buf[1] = NULL; } else if (ch_state == MHI_STATE_DISCONNECTED) { buf[0] = kasprintf(GFP_KERNEL, "MHI_CHANNEL_STATE_%d=DISCONNECTED", ch_id); buf[1] = NULL; } else { uci_log(UCI_DBG_ERROR, "Unsupported chan state %d\n", ch_state); return; } if (!buf[0]) { uci_log(UCI_DBG_ERROR, "kasprintf failed for uevent buf!\n"); return; } rc = kobject_uevent_env(&mhi->dev->kobj, KOBJ_CHANGE, buf); if (rc) uci_log(UCI_DBG_ERROR, "Sending uevent failed for chan %d\n", ch_id); kfree(buf[0]); } EXPORT_SYMBOL(mhi_uci_chan_state_notify); void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason) { struct uci_ctrl *uci_ctrl_handle = NULL; Loading