Loading drivers/soc/qcom/glink.c +47 −34 Original line number Original line Diff line number Diff line /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and Loading @@ -12,6 +12,7 @@ #include <asm/arch_timer.h> #include <asm/arch_timer.h> #include <linux/err.h> #include <linux/err.h> #include <linux/ipc_logging.h> #include <linux/ipc_logging.h> #include <linux/kthread.h> #include <linux/list.h> #include <linux/list.h> #include <linux/spinlock.h> #include <linux/spinlock.h> #include <linux/module.h> #include <linux/module.h> Loading @@ -36,6 +37,7 @@ #define GLINK_QOS_DEF_NUM_PRIORITY 1 #define GLINK_QOS_DEF_NUM_PRIORITY 1 #define GLINK_QOS_DEF_MTU 2048 #define GLINK_QOS_DEF_MTU 2048 #define GLINK_KTHREAD_PRIO 1 /** /** * struct glink_qos_priority_bin - Packet Scheduler's priority bucket * struct glink_qos_priority_bin - Packet Scheduler's priority bucket * @max_rate_kBps: Maximum rate supported by the priority bucket. * @max_rate_kBps: Maximum rate supported by the priority bucket. Loading Loading @@ -78,8 +80,9 @@ struct glink_qos_priority_bin { * created channel * created channel * @max_cid: maximum number of channel identifiers supported * @max_cid: maximum number of channel identifiers supported * @max_iid: maximum number of intent identifiers supported * @max_iid: maximum number of intent identifiers supported * @tx_work: work item to process @tx_ready * @tx_kwork: work item to process @tx_ready * @tx_wq: workqueue to run @tx_work * @tx_wq: workqueue to run @tx_kwork * @tx_task: handle to the running kthread * @channels: list of all existing channels on this transport * @channels: list of all existing channels on this transport * @mtu: MTU supported by this transport. * @mtu: MTU supported by this transport. * @token_count: Number of tokens to be assigned per assignment. * @token_count: Number of tokens to be assigned per assignment. Loading Loading @@ -119,9 +122,9 @@ struct glink_core_xprt_ctx { uint32_t max_cid; uint32_t max_cid; uint32_t max_iid; uint32_t max_iid; struct work_struct tx_work; struct kthread_work tx_kwork; struct workqueue_struct *tx_wq; struct kthread_worker tx_wq; struct task_struct *tx_task; size_t mtu; size_t mtu; uint32_t token_count; uint32_t token_count; unsigned long curr_qos_rate_kBps; unsigned long curr_qos_rate_kBps; Loading Loading @@ -340,7 +343,7 @@ static int xprt_single_threaded_tx(struct glink_core_xprt_ctx *xprt_ptr, struct channel_ctx *ch_ptr, struct channel_ctx *ch_ptr, struct glink_core_tx_pkt *tx_info); struct glink_core_tx_pkt *tx_info); static void tx_work_func(struct work_struct *work); static void tx_func(struct kthread_work *work); static struct channel_ctx *ch_name_to_ch_ctx_create( static struct channel_ctx *ch_name_to_ch_ctx_create( struct glink_core_xprt_ctx *xprt_ctx, struct glink_core_xprt_ctx *xprt_ctx, Loading Loading @@ -3389,7 +3392,8 @@ void glink_xprt_ctx_release(struct rwref_lock *xprt_st_lock) xprt_rm_dbgfs.par_name = "xprt"; xprt_rm_dbgfs.par_name = "xprt"; glink_debugfs_remove_recur(&xprt_rm_dbgfs); glink_debugfs_remove_recur(&xprt_rm_dbgfs); GLINK_INFO("%s: xprt debugfs removec\n", __func__); GLINK_INFO("%s: xprt debugfs removec\n", __func__); destroy_workqueue(xprt_ctx->tx_wq); kthread_stop(xprt_ctx->tx_task); xprt_ctx->tx_task = NULL; glink_core_deinit_xprt_qos_cfg(xprt_ctx); glink_core_deinit_xprt_qos_cfg(xprt_ctx); kfree(xprt_ctx); kfree(xprt_ctx); xprt_ctx = NULL; xprt_ctx = NULL; Loading Loading @@ -3557,7 +3561,7 @@ static int glink_core_init_xprt_qos_cfg(struct glink_core_xprt_ctx *xprt_ptr, struct glink_core_transport_cfg *cfg) struct glink_core_transport_cfg *cfg) { { int i; int i; struct sched_param param = { .sched_priority = GLINK_KTHREAD_PRIO }; xprt_ptr->mtu = cfg->mtu ? cfg->mtu : GLINK_QOS_DEF_MTU; xprt_ptr->mtu = cfg->mtu ? cfg->mtu : GLINK_QOS_DEF_MTU; xprt_ptr->num_priority = cfg->num_flows ? cfg->num_flows : xprt_ptr->num_priority = cfg->num_flows ? cfg->num_flows : GLINK_QOS_DEF_NUM_PRIORITY; GLINK_QOS_DEF_NUM_PRIORITY; Loading @@ -3567,6 +3571,9 @@ static int glink_core_init_xprt_qos_cfg(struct glink_core_xprt_ctx *xprt_ptr, xprt_ptr->prio_bin = kzalloc(xprt_ptr->num_priority * xprt_ptr->prio_bin = kzalloc(xprt_ptr->num_priority * sizeof(struct glink_qos_priority_bin), sizeof(struct glink_qos_priority_bin), GFP_KERNEL); GFP_KERNEL); if (xprt_ptr->num_priority > 1) sched_setscheduler(xprt_ptr->tx_task, SCHED_FIFO, ¶m); if (!xprt_ptr->prio_bin) { if (!xprt_ptr->prio_bin) { GLINK_ERR("%s: unable to allocate priority bins\n", __func__); GLINK_ERR("%s: unable to allocate priority bins\n", __func__); return -ENOMEM; return -ENOMEM; Loading Loading @@ -3683,21 +3690,26 @@ int glink_core_register_transport(struct glink_transport_if *if_ptr, xprt_ptr->local_state = GLINK_XPRT_DOWN; xprt_ptr->local_state = GLINK_XPRT_DOWN; xprt_ptr->remote_neg_completed = false; xprt_ptr->remote_neg_completed = false; INIT_LIST_HEAD(&xprt_ptr->channels); INIT_LIST_HEAD(&xprt_ptr->channels); ret = glink_core_init_xprt_qos_cfg(xprt_ptr, cfg); if (ret < 0) { kfree(xprt_ptr); return ret; } spin_lock_init(&xprt_ptr->tx_ready_lock_lhb2); spin_lock_init(&xprt_ptr->tx_ready_lock_lhb2); mutex_init(&xprt_ptr->xprt_dbgfs_lock_lhb3); mutex_init(&xprt_ptr->xprt_dbgfs_lock_lhb3); INIT_WORK(&xprt_ptr->tx_work, tx_work_func); init_kthread_work(&xprt_ptr->tx_kwork, tx_func); xprt_ptr->tx_wq = create_singlethread_workqueue("glink_tx"); init_kthread_worker(&xprt_ptr->tx_wq); if (IS_ERR_OR_NULL(xprt_ptr->tx_wq)) { xprt_ptr->tx_task = kthread_run(kthread_worker_fn, GLINK_ERR("%s: unable to allocate workqueue\n", __func__); &xprt_ptr->tx_wq, "%s_%s_glink_tx", xprt_ptr->edge, xprt_ptr->name); if (IS_ERR_OR_NULL(xprt_ptr->tx_task)) { GLINK_ERR("%s: unable to run thread\n", __func__); glink_core_deinit_xprt_qos_cfg(xprt_ptr); glink_core_deinit_xprt_qos_cfg(xprt_ptr); kfree(xprt_ptr); kfree(xprt_ptr); return -ENOMEM; return -ENOMEM; } } ret = glink_core_init_xprt_qos_cfg(xprt_ptr, cfg); if (ret < 0) { kfree(xprt_ptr); return ret; } INIT_DELAYED_WORK(&xprt_ptr->pm_qos_work, glink_pm_qos_cancel_worker); INIT_DELAYED_WORK(&xprt_ptr->pm_qos_work, glink_pm_qos_cancel_worker); pm_qos_add_request(&xprt_ptr->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, pm_qos_add_request(&xprt_ptr->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); PM_QOS_DEFAULT_VALUE); Loading Loading @@ -3789,7 +3801,7 @@ static void glink_core_link_down(struct glink_transport_if *if_ptr) GLINK_DBG_XPRT(xprt_ptr, GLINK_DBG_XPRT(xprt_ptr, "%s: Flushing work from tx_wq. Thread: %u\n", __func__, "%s: Flushing work from tx_wq. Thread: %u\n", __func__, current->pid); current->pid); flush_workqueue(xprt_ptr->tx_wq); flush_kthread_worker(&xprt_ptr->tx_wq); glink_core_channel_cleanup(xprt_ptr); glink_core_channel_cleanup(xprt_ptr); check_link_notifier_and_notify(xprt_ptr, GLINK_LINK_STATE_DOWN); check_link_notifier_and_notify(xprt_ptr, GLINK_LINK_STATE_DOWN); } } Loading Loading @@ -4557,6 +4569,7 @@ static void glink_core_rx_cmd_ch_remote_close( { { struct channel_ctx *ctx; struct channel_ctx *ctx; bool is_ch_fully_closed; bool is_ch_fully_closed; struct glink_core_xprt_ctx *xprt_ptr = if_ptr->glink_core_priv; ctx = xprt_rcid_to_ch_ctx_get(if_ptr->glink_core_priv, rcid); ctx = xprt_rcid_to_ch_ctx_get(if_ptr->glink_core_priv, rcid); if (!ctx) { if (!ctx) { Loading @@ -4583,7 +4596,7 @@ static void glink_core_rx_cmd_ch_remote_close( if (is_ch_fully_closed) { if (is_ch_fully_closed) { glink_delete_ch_from_list(ctx, true); glink_delete_ch_from_list(ctx, true); flush_workqueue(ctx->transport_ptr->tx_wq); flush_kthread_worker(&xprt_ptr->tx_wq); } } rwref_put(&ctx->ch_state_lhc0); rwref_put(&ctx->ch_state_lhc0); } } Loading @@ -4599,6 +4612,7 @@ static void glink_core_rx_cmd_ch_close_ack(struct glink_transport_if *if_ptr, { { struct channel_ctx *ctx; struct channel_ctx *ctx; bool is_ch_fully_closed; bool is_ch_fully_closed; struct glink_core_xprt_ctx *xprt_ptr = if_ptr->glink_core_priv; ctx = xprt_lcid_to_ch_ctx_get(if_ptr->glink_core_priv, lcid); ctx = xprt_lcid_to_ch_ctx_get(if_ptr->glink_core_priv, lcid); if (!ctx) { if (!ctx) { Loading @@ -4620,7 +4634,7 @@ static void glink_core_rx_cmd_ch_close_ack(struct glink_transport_if *if_ptr, is_ch_fully_closed = glink_core_ch_close_ack_common(ctx); is_ch_fully_closed = glink_core_ch_close_ack_common(ctx); if (is_ch_fully_closed) { if (is_ch_fully_closed) { glink_delete_ch_from_list(ctx, true); glink_delete_ch_from_list(ctx, true); flush_workqueue(ctx->transport_ptr->tx_wq); flush_kthread_worker(&xprt_ptr->tx_wq); } } rwref_put(&ctx->ch_state_lhc0); rwref_put(&ctx->ch_state_lhc0); } } Loading Loading @@ -4932,8 +4946,7 @@ static void xprt_schedule_tx(struct glink_core_xprt_ctx *xprt_ptr, spin_unlock(&ch_ptr->tx_lists_lock_lhc3); spin_unlock(&ch_ptr->tx_lists_lock_lhc3); spin_unlock_irqrestore(&xprt_ptr->tx_ready_lock_lhb2, flags); spin_unlock_irqrestore(&xprt_ptr->tx_ready_lock_lhb2, flags); queue_kthread_work(&xprt_ptr->tx_wq, &xprt_ptr->tx_kwork); queue_work(xprt_ptr->tx_wq, &xprt_ptr->tx_work); } } /** /** Loading Loading @@ -5114,14 +5127,11 @@ static int glink_scheduler_tx(struct channel_ctx *ctx, return ret; return ret; } } /** * tx_work_func() - Transmit worker /**Actual Transmit function * @work: Linux work structure **/ */ static void tx_func(struct kthread_work *work) static void tx_work_func(struct work_struct *work) { { struct glink_core_xprt_ctx *xprt_ptr = container_of(work, struct glink_core_xprt_ctx, tx_work); struct channel_ctx *ch_ptr; struct channel_ctx *ch_ptr; uint32_t prio; uint32_t prio; uint32_t tx_ready_head_prio; uint32_t tx_ready_head_prio; Loading @@ -5129,6 +5139,8 @@ static void tx_work_func(struct work_struct *work) struct channel_ctx *tx_ready_head = NULL; struct channel_ctx *tx_ready_head = NULL; bool transmitted_successfully = true; bool transmitted_successfully = true; unsigned long flags; unsigned long flags; struct glink_core_xprt_ctx *xprt_ptr = container_of(work, struct glink_core_xprt_ctx, tx_kwork); GLINK_PERF("%s: worker starting\n", __func__); GLINK_PERF("%s: worker starting\n", __func__); Loading Loading @@ -5214,8 +5226,9 @@ static void tx_work_func(struct work_struct *work) static void glink_core_tx_resume(struct glink_transport_if *if_ptr) static void glink_core_tx_resume(struct glink_transport_if *if_ptr) { { queue_work(if_ptr->glink_core_priv->tx_wq, struct glink_core_xprt_ctx *xprt_ptr = if_ptr->glink_core_priv; &if_ptr->glink_core_priv->tx_work); queue_kthread_work(&xprt_ptr->tx_wq, &xprt_ptr->tx_kwork); } } /** /** Loading drivers/soc/qcom/glink_smd_xprt.c +51 −10 Original line number Original line Diff line number Diff line Loading @@ -10,6 +10,7 @@ * GNU General Public License for more details. * GNU General Public License for more details. */ */ #include <linux/delay.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/list.h> #include <linux/module.h> #include <linux/module.h> Loading Loading @@ -140,6 +141,7 @@ struct channel { uint32_t lcid; uint32_t lcid; uint32_t rcid; uint32_t rcid; struct mutex ch_probe_lock; struct mutex ch_probe_lock; struct mutex ch_tasklet_lock; bool wait_for_probe; bool wait_for_probe; bool had_probed; bool had_probed; struct edge_info *edge; struct edge_info *edge; Loading @@ -149,7 +151,7 @@ struct channel { spinlock_t intents_lock; spinlock_t intents_lock; uint32_t next_intent_id; uint32_t next_intent_id; struct workqueue_struct *wq; struct workqueue_struct *wq; struct work_struct work; struct tasklet_struct data_tasklet; struct intent_info *cur_intent; struct intent_info *cur_intent; bool intent_req; bool intent_req; bool is_closing; bool is_closing; Loading @@ -159,6 +161,7 @@ struct channel { spinlock_t rx_data_lock; spinlock_t rx_data_lock; bool streaming_ch; bool streaming_ch; bool tx_resume_needed; bool tx_resume_needed; bool is_tasklet_enabled; }; }; /** /** Loading Loading @@ -230,7 +233,7 @@ static struct glink_core_version versions[] = { static LIST_HEAD(pdrv_list); static LIST_HEAD(pdrv_list); static DEFINE_MUTEX(pdrv_list_mutex); static DEFINE_MUTEX(pdrv_list_mutex); static void process_data_event(struct work_struct *work); static void process_data_event(unsigned long param); static int add_platform_driver(struct channel *ch); static int add_platform_driver(struct channel *ch); static void smd_data_ch_close(struct channel *ch); static void smd_data_ch_close(struct channel *ch); Loading Loading @@ -324,11 +327,17 @@ static void process_ctl_event(struct work_struct *work) strlcpy(ch->name, name, GLINK_NAME_SIZE); strlcpy(ch->name, name, GLINK_NAME_SIZE); ch->edge = einfo; ch->edge = einfo; mutex_init(&ch->ch_probe_lock); mutex_init(&ch->ch_probe_lock); mutex_init(&ch->ch_tasklet_lock); INIT_LIST_HEAD(&ch->intents); INIT_LIST_HEAD(&ch->intents); INIT_LIST_HEAD(&ch->used_intents); INIT_LIST_HEAD(&ch->used_intents); spin_lock_init(&ch->intents_lock); spin_lock_init(&ch->intents_lock); spin_lock_init(&ch->rx_data_lock); spin_lock_init(&ch->rx_data_lock); INIT_WORK(&ch->work, process_data_event); mutex_lock(&ch->ch_tasklet_lock); tasklet_init(&ch->data_tasklet, process_data_event, (unsigned long)ch); tasklet_disable(&ch->data_tasklet); ch->is_tasklet_enabled = false; mutex_unlock(&ch->ch_tasklet_lock); ch->wq = create_singlethread_workqueue( ch->wq = create_singlethread_workqueue( ch->name); ch->name); if (!ch->wq) { if (!ch->wq) { Loading Loading @@ -362,6 +371,7 @@ static void process_ctl_event(struct work_struct *work) } else { } else { spin_unlock_irqrestore( spin_unlock_irqrestore( &einfo->channels_lock, flags); &einfo->channels_lock, flags); tasklet_kill(&temp_ch->data_tasklet); destroy_workqueue(temp_ch->wq); destroy_workqueue(temp_ch->wq); kfree(temp_ch); kfree(temp_ch); } } Loading Loading @@ -602,6 +612,12 @@ static void process_open_event(struct work_struct *work) SMD_TRANS_XPRT_ID); SMD_TRANS_XPRT_ID); mutex_unlock(&einfo->rx_cmd_lock); mutex_unlock(&einfo->rx_cmd_lock); } } mutex_lock(&ch->ch_tasklet_lock); if (!ch->is_tasklet_enabled) { tasklet_enable(&ch->data_tasklet); ch->is_tasklet_enabled = true; } mutex_unlock(&ch->ch_tasklet_lock); kfree(ch_work); kfree(ch_work); } } Loading @@ -626,6 +642,12 @@ static void process_close_event(struct work_struct *work) ch->rcid); ch->rcid); mutex_unlock(&einfo->rx_cmd_lock); mutex_unlock(&einfo->rx_cmd_lock); } } mutex_lock(&ch->ch_tasklet_lock); if (ch->is_tasklet_enabled) { tasklet_disable(&ch->data_tasklet); ch->is_tasklet_enabled = false; } mutex_unlock(&ch->ch_tasklet_lock); ch->rcid = 0; ch->rcid = 0; } } Loading Loading @@ -696,9 +718,9 @@ static void process_reopen_event(struct work_struct *work) /** /** * process_data_event() - process a data event task * process_data_event() - process a data event task * @work: The data task to process. * @param: Pointer to the channel in long format. */ */ static void process_data_event(struct work_struct *work) static void process_data_event(unsigned long param) { { struct channel *ch; struct channel *ch; struct edge_info *einfo; struct edge_info *einfo; Loading @@ -710,7 +732,7 @@ static void process_data_event(struct work_struct *work) unsigned long intents_flags; unsigned long intents_flags; unsigned long rx_data_flags; unsigned long rx_data_flags; ch = container_of(work, struct channel, work); ch = (struct channel *)param; einfo = ch->edge; einfo = ch->edge; if (ch->tx_resume_needed && smd_write_avail(ch->smd_ch) > 0) { if (ch->tx_resume_needed && smd_write_avail(ch->smd_ch) > 0) { Loading Loading @@ -810,7 +832,7 @@ static void smd_data_ch_notify(void *priv, unsigned event) switch (event) { switch (event) { case SMD_EVENT_DATA: case SMD_EVENT_DATA: queue_work(ch->wq, &ch->work); tasklet_hi_schedule(&ch->data_tasklet); break; break; case SMD_EVENT_OPEN: case SMD_EVENT_OPEN: work = kmalloc(sizeof(*work), GFP_ATOMIC); work = kmalloc(sizeof(*work), GFP_ATOMIC); Loading Loading @@ -883,6 +905,12 @@ static void smd_data_ch_close(struct channel *ch) ch->is_closing = true; ch->is_closing = true; ch->tx_resume_needed = false; ch->tx_resume_needed = false; mutex_lock(&ch->ch_tasklet_lock); if (ch->is_tasklet_enabled) { tasklet_disable(&ch->data_tasklet); ch->is_tasklet_enabled = false; } mutex_unlock(&ch->ch_tasklet_lock); flush_workqueue(ch->wq); flush_workqueue(ch->wq); mutex_lock(&ch->ch_probe_lock); mutex_lock(&ch->ch_probe_lock); Loading Loading @@ -1186,11 +1214,17 @@ static int tx_cmd_ch_open(struct glink_transport_if *if_ptr, uint32_t lcid, strlcpy(ch->name, name, GLINK_NAME_SIZE); strlcpy(ch->name, name, GLINK_NAME_SIZE); ch->edge = einfo; ch->edge = einfo; mutex_init(&ch->ch_probe_lock); mutex_init(&ch->ch_probe_lock); mutex_init(&ch->ch_tasklet_lock); INIT_LIST_HEAD(&ch->intents); INIT_LIST_HEAD(&ch->intents); INIT_LIST_HEAD(&ch->used_intents); INIT_LIST_HEAD(&ch->used_intents); spin_lock_init(&ch->intents_lock); spin_lock_init(&ch->intents_lock); spin_lock_init(&ch->rx_data_lock); spin_lock_init(&ch->rx_data_lock); INIT_WORK(&ch->work, process_data_event); mutex_lock(&ch->ch_tasklet_lock); tasklet_init(&ch->data_tasklet, process_data_event, (unsigned long)ch); tasklet_disable(&ch->data_tasklet); ch->is_tasklet_enabled = false; mutex_unlock(&ch->ch_tasklet_lock); ch->wq = create_singlethread_workqueue(ch->name); ch->wq = create_singlethread_workqueue(ch->name); if (!ch->wq) { if (!ch->wq) { SMDXPRT_ERR(einfo, SMDXPRT_ERR(einfo, Loading Loading @@ -1220,6 +1254,7 @@ static int tx_cmd_ch_open(struct glink_transport_if *if_ptr, uint32_t lcid, spin_unlock_irqrestore(&einfo->channels_lock, flags); spin_unlock_irqrestore(&einfo->channels_lock, flags); } else { } else { spin_unlock_irqrestore(&einfo->channels_lock, flags); spin_unlock_irqrestore(&einfo->channels_lock, flags); tasklet_kill(&temp_ch->data_tasklet); destroy_workqueue(temp_ch->wq); destroy_workqueue(temp_ch->wq); kfree(temp_ch); kfree(temp_ch); } } Loading Loading @@ -1463,6 +1498,12 @@ static int ssr(struct glink_transport_if *if_ptr) list_for_each_entry(ch, &einfo->channels, node) { list_for_each_entry(ch, &einfo->channels, node) { spin_unlock_irqrestore(&einfo->channels_lock, flags); spin_unlock_irqrestore(&einfo->channels_lock, flags); ch->is_closing = true; ch->is_closing = true; mutex_lock(&ch->ch_tasklet_lock); if (ch->is_tasklet_enabled) { tasklet_disable(&ch->data_tasklet); ch->is_tasklet_enabled = false; } mutex_unlock(&ch->ch_tasklet_lock); flush_workqueue(ch->wq); flush_workqueue(ch->wq); mutex_lock(&ch->ch_probe_lock); mutex_lock(&ch->ch_probe_lock); ch->wait_for_probe = false; ch->wait_for_probe = false; Loading Loading @@ -1568,7 +1609,7 @@ static void check_and_resume_rx(struct channel *ch, size_t intent_size) { { if (ch->intent_req && ch->intent_req_size <= intent_size) { if (ch->intent_req && ch->intent_req_size <= intent_size) { ch->intent_req = false; ch->intent_req = false; queue_work(ch->wq, &ch->work); tasklet_hi_schedule(&ch->data_tasklet); } } } } Loading Loading @@ -1895,7 +1936,7 @@ static int poll(struct glink_transport_if *if_ptr, uint32_t lcid) spin_unlock_irqrestore(&einfo->channels_lock, flags); spin_unlock_irqrestore(&einfo->channels_lock, flags); rc = smd_is_pkt_avail(ch->smd_ch); rc = smd_is_pkt_avail(ch->smd_ch); if (rc == 1) if (rc == 1) process_data_event(&ch->work); process_data_event((unsigned long)ch); return rc; return rc; } } Loading drivers/soc/qcom/glink_smem_native_xprt.c +24 −2 Original line number Original line Diff line number Diff line Loading @@ -169,7 +169,10 @@ struct mailbox_config_info { * been sent, and a response is pending from the * been sent, and a response is pending from the * remote side. Protected by @write_lock. * remote side. Protected by @write_lock. * @kwork: Work to be executed when an irq is received. * @kwork: Work to be executed when an irq is received. * @kworker: Handle to the entity processing @kwork. * @kworker: Handle to the entity processing of deferred commands. * @tasklet Handle to tasklet to process incoming data packets in atomic manner. * @task: Handle to the task context used to run @kworker. * @task: Handle to the task context used to run @kworker. * @use_ref: Active uses of this transport use this to grab * @use_ref: Active uses of this transport use this to grab * a reference. Used for ssr synchronization. * a reference. Used for ssr synchronization. Loading Loading @@ -210,6 +213,7 @@ struct edge_info { struct kthread_work kwork; struct kthread_work kwork; struct kthread_worker kworker; struct kthread_worker kworker; struct task_struct *task; struct task_struct *task; struct tasklet_struct tasklet; struct srcu_struct use_ref; struct srcu_struct use_ref; bool in_ssr; bool in_ssr; spinlock_t rx_lock; spinlock_t rx_lock; Loading Loading @@ -1144,6 +1148,18 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) srcu_read_unlock(&einfo->use_ref, rcu_id); srcu_read_unlock(&einfo->use_ref, rcu_id); } } /** * rx_worker_atomic() - worker function to process received command in atomic * context. * @param: The param parameter passed during initialization of the tasklet. */ static void rx_worker_atomic(unsigned long param) { struct edge_info *einfo = (struct edge_info *)param; __rx_worker(einfo, true); } /** /** * rx_worker() - worker function to process received commands * rx_worker() - worker function to process received commands * @work: kwork associated with the edge to process commands on. * @work: kwork associated with the edge to process commands on. Loading @@ -1163,7 +1179,7 @@ irqreturn_t irq_handler(int irq, void *priv) if (einfo->rx_reset_reg) if (einfo->rx_reset_reg) writel_relaxed(einfo->out_irq_mask, einfo->rx_reset_reg); writel_relaxed(einfo->out_irq_mask, einfo->rx_reset_reg); queue_kthread_work(&einfo->kworker, &einfo->kwork); tasklet_hi_schedule(&einfo->tasklet); einfo->rx_irq_count++; einfo->rx_irq_count++; return IRQ_HANDLED; return IRQ_HANDLED; Loading Loading @@ -2244,6 +2260,7 @@ static int glink_smem_native_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); init_waitqueue_head(&einfo->tx_blocked_queue); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_worker(&einfo->kworker); init_kthread_worker(&einfo->kworker); tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->read_from_fifo = read_from_fifo; einfo->read_from_fifo = read_from_fifo; einfo->write_to_fifo = write_to_fifo; einfo->write_to_fifo = write_to_fifo; init_srcu_struct(&einfo->use_ref); init_srcu_struct(&einfo->use_ref); Loading Loading @@ -2344,6 +2361,7 @@ smem_alloc_fail: flush_kthread_worker(&einfo->kworker); flush_kthread_worker(&einfo->kworker); kthread_stop(einfo->task); kthread_stop(einfo->task); einfo->task = NULL; einfo->task = NULL; tasklet_kill(&einfo->tasklet); kthread_fail: kthread_fail: iounmap(einfo->out_irq_reg); iounmap(einfo->out_irq_reg); ioremap_fail: ioremap_fail: Loading Loading @@ -2429,6 +2447,7 @@ static int glink_rpm_native_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); init_waitqueue_head(&einfo->tx_blocked_queue); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_worker(&einfo->kworker); init_kthread_worker(&einfo->kworker); tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->intentless = true; einfo->intentless = true; einfo->read_from_fifo = memcpy32_fromio; einfo->read_from_fifo = memcpy32_fromio; einfo->write_to_fifo = memcpy32_toio; einfo->write_to_fifo = memcpy32_toio; Loading Loading @@ -2590,6 +2609,7 @@ toc_init_fail: flush_kthread_worker(&einfo->kworker); flush_kthread_worker(&einfo->kworker); kthread_stop(einfo->task); kthread_stop(einfo->task); einfo->task = NULL; einfo->task = NULL; tasklet_kill(&einfo->tasklet); kthread_fail: kthread_fail: iounmap(msgram); iounmap(msgram); msgram_ioremap_fail: msgram_ioremap_fail: Loading Loading @@ -2718,6 +2738,7 @@ static int glink_mailbox_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); init_waitqueue_head(&einfo->tx_blocked_queue); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_worker(&einfo->kworker); init_kthread_worker(&einfo->kworker); tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->read_from_fifo = read_from_fifo; einfo->read_from_fifo = read_from_fifo; einfo->write_to_fifo = write_to_fifo; einfo->write_to_fifo = write_to_fifo; init_srcu_struct(&einfo->use_ref); init_srcu_struct(&einfo->use_ref); Loading Loading @@ -2839,6 +2860,7 @@ smem_alloc_fail: flush_kthread_worker(&einfo->kworker); flush_kthread_worker(&einfo->kworker); kthread_stop(einfo->task); kthread_stop(einfo->task); einfo->task = NULL; einfo->task = NULL; tasklet_kill(&einfo->tasklet); kthread_fail: kthread_fail: iounmap(einfo->rx_reset_reg); iounmap(einfo->rx_reset_reg); rx_reset_ioremap_fail: rx_reset_ioremap_fail: Loading Loading
drivers/soc/qcom/glink.c +47 −34 Original line number Original line Diff line number Diff line /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and Loading @@ -12,6 +12,7 @@ #include <asm/arch_timer.h> #include <asm/arch_timer.h> #include <linux/err.h> #include <linux/err.h> #include <linux/ipc_logging.h> #include <linux/ipc_logging.h> #include <linux/kthread.h> #include <linux/list.h> #include <linux/list.h> #include <linux/spinlock.h> #include <linux/spinlock.h> #include <linux/module.h> #include <linux/module.h> Loading @@ -36,6 +37,7 @@ #define GLINK_QOS_DEF_NUM_PRIORITY 1 #define GLINK_QOS_DEF_NUM_PRIORITY 1 #define GLINK_QOS_DEF_MTU 2048 #define GLINK_QOS_DEF_MTU 2048 #define GLINK_KTHREAD_PRIO 1 /** /** * struct glink_qos_priority_bin - Packet Scheduler's priority bucket * struct glink_qos_priority_bin - Packet Scheduler's priority bucket * @max_rate_kBps: Maximum rate supported by the priority bucket. * @max_rate_kBps: Maximum rate supported by the priority bucket. Loading Loading @@ -78,8 +80,9 @@ struct glink_qos_priority_bin { * created channel * created channel * @max_cid: maximum number of channel identifiers supported * @max_cid: maximum number of channel identifiers supported * @max_iid: maximum number of intent identifiers supported * @max_iid: maximum number of intent identifiers supported * @tx_work: work item to process @tx_ready * @tx_kwork: work item to process @tx_ready * @tx_wq: workqueue to run @tx_work * @tx_wq: workqueue to run @tx_kwork * @tx_task: handle to the running kthread * @channels: list of all existing channels on this transport * @channels: list of all existing channels on this transport * @mtu: MTU supported by this transport. * @mtu: MTU supported by this transport. * @token_count: Number of tokens to be assigned per assignment. * @token_count: Number of tokens to be assigned per assignment. Loading Loading @@ -119,9 +122,9 @@ struct glink_core_xprt_ctx { uint32_t max_cid; uint32_t max_cid; uint32_t max_iid; uint32_t max_iid; struct work_struct tx_work; struct kthread_work tx_kwork; struct workqueue_struct *tx_wq; struct kthread_worker tx_wq; struct task_struct *tx_task; size_t mtu; size_t mtu; uint32_t token_count; uint32_t token_count; unsigned long curr_qos_rate_kBps; unsigned long curr_qos_rate_kBps; Loading Loading @@ -340,7 +343,7 @@ static int xprt_single_threaded_tx(struct glink_core_xprt_ctx *xprt_ptr, struct channel_ctx *ch_ptr, struct channel_ctx *ch_ptr, struct glink_core_tx_pkt *tx_info); struct glink_core_tx_pkt *tx_info); static void tx_work_func(struct work_struct *work); static void tx_func(struct kthread_work *work); static struct channel_ctx *ch_name_to_ch_ctx_create( static struct channel_ctx *ch_name_to_ch_ctx_create( struct glink_core_xprt_ctx *xprt_ctx, struct glink_core_xprt_ctx *xprt_ctx, Loading Loading @@ -3389,7 +3392,8 @@ void glink_xprt_ctx_release(struct rwref_lock *xprt_st_lock) xprt_rm_dbgfs.par_name = "xprt"; xprt_rm_dbgfs.par_name = "xprt"; glink_debugfs_remove_recur(&xprt_rm_dbgfs); glink_debugfs_remove_recur(&xprt_rm_dbgfs); GLINK_INFO("%s: xprt debugfs removec\n", __func__); GLINK_INFO("%s: xprt debugfs removec\n", __func__); destroy_workqueue(xprt_ctx->tx_wq); kthread_stop(xprt_ctx->tx_task); xprt_ctx->tx_task = NULL; glink_core_deinit_xprt_qos_cfg(xprt_ctx); glink_core_deinit_xprt_qos_cfg(xprt_ctx); kfree(xprt_ctx); kfree(xprt_ctx); xprt_ctx = NULL; xprt_ctx = NULL; Loading Loading @@ -3557,7 +3561,7 @@ static int glink_core_init_xprt_qos_cfg(struct glink_core_xprt_ctx *xprt_ptr, struct glink_core_transport_cfg *cfg) struct glink_core_transport_cfg *cfg) { { int i; int i; struct sched_param param = { .sched_priority = GLINK_KTHREAD_PRIO }; xprt_ptr->mtu = cfg->mtu ? cfg->mtu : GLINK_QOS_DEF_MTU; xprt_ptr->mtu = cfg->mtu ? cfg->mtu : GLINK_QOS_DEF_MTU; xprt_ptr->num_priority = cfg->num_flows ? cfg->num_flows : xprt_ptr->num_priority = cfg->num_flows ? cfg->num_flows : GLINK_QOS_DEF_NUM_PRIORITY; GLINK_QOS_DEF_NUM_PRIORITY; Loading @@ -3567,6 +3571,9 @@ static int glink_core_init_xprt_qos_cfg(struct glink_core_xprt_ctx *xprt_ptr, xprt_ptr->prio_bin = kzalloc(xprt_ptr->num_priority * xprt_ptr->prio_bin = kzalloc(xprt_ptr->num_priority * sizeof(struct glink_qos_priority_bin), sizeof(struct glink_qos_priority_bin), GFP_KERNEL); GFP_KERNEL); if (xprt_ptr->num_priority > 1) sched_setscheduler(xprt_ptr->tx_task, SCHED_FIFO, ¶m); if (!xprt_ptr->prio_bin) { if (!xprt_ptr->prio_bin) { GLINK_ERR("%s: unable to allocate priority bins\n", __func__); GLINK_ERR("%s: unable to allocate priority bins\n", __func__); return -ENOMEM; return -ENOMEM; Loading Loading @@ -3683,21 +3690,26 @@ int glink_core_register_transport(struct glink_transport_if *if_ptr, xprt_ptr->local_state = GLINK_XPRT_DOWN; xprt_ptr->local_state = GLINK_XPRT_DOWN; xprt_ptr->remote_neg_completed = false; xprt_ptr->remote_neg_completed = false; INIT_LIST_HEAD(&xprt_ptr->channels); INIT_LIST_HEAD(&xprt_ptr->channels); ret = glink_core_init_xprt_qos_cfg(xprt_ptr, cfg); if (ret < 0) { kfree(xprt_ptr); return ret; } spin_lock_init(&xprt_ptr->tx_ready_lock_lhb2); spin_lock_init(&xprt_ptr->tx_ready_lock_lhb2); mutex_init(&xprt_ptr->xprt_dbgfs_lock_lhb3); mutex_init(&xprt_ptr->xprt_dbgfs_lock_lhb3); INIT_WORK(&xprt_ptr->tx_work, tx_work_func); init_kthread_work(&xprt_ptr->tx_kwork, tx_func); xprt_ptr->tx_wq = create_singlethread_workqueue("glink_tx"); init_kthread_worker(&xprt_ptr->tx_wq); if (IS_ERR_OR_NULL(xprt_ptr->tx_wq)) { xprt_ptr->tx_task = kthread_run(kthread_worker_fn, GLINK_ERR("%s: unable to allocate workqueue\n", __func__); &xprt_ptr->tx_wq, "%s_%s_glink_tx", xprt_ptr->edge, xprt_ptr->name); if (IS_ERR_OR_NULL(xprt_ptr->tx_task)) { GLINK_ERR("%s: unable to run thread\n", __func__); glink_core_deinit_xprt_qos_cfg(xprt_ptr); glink_core_deinit_xprt_qos_cfg(xprt_ptr); kfree(xprt_ptr); kfree(xprt_ptr); return -ENOMEM; return -ENOMEM; } } ret = glink_core_init_xprt_qos_cfg(xprt_ptr, cfg); if (ret < 0) { kfree(xprt_ptr); return ret; } INIT_DELAYED_WORK(&xprt_ptr->pm_qos_work, glink_pm_qos_cancel_worker); INIT_DELAYED_WORK(&xprt_ptr->pm_qos_work, glink_pm_qos_cancel_worker); pm_qos_add_request(&xprt_ptr->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, pm_qos_add_request(&xprt_ptr->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); PM_QOS_DEFAULT_VALUE); Loading Loading @@ -3789,7 +3801,7 @@ static void glink_core_link_down(struct glink_transport_if *if_ptr) GLINK_DBG_XPRT(xprt_ptr, GLINK_DBG_XPRT(xprt_ptr, "%s: Flushing work from tx_wq. Thread: %u\n", __func__, "%s: Flushing work from tx_wq. Thread: %u\n", __func__, current->pid); current->pid); flush_workqueue(xprt_ptr->tx_wq); flush_kthread_worker(&xprt_ptr->tx_wq); glink_core_channel_cleanup(xprt_ptr); glink_core_channel_cleanup(xprt_ptr); check_link_notifier_and_notify(xprt_ptr, GLINK_LINK_STATE_DOWN); check_link_notifier_and_notify(xprt_ptr, GLINK_LINK_STATE_DOWN); } } Loading Loading @@ -4557,6 +4569,7 @@ static void glink_core_rx_cmd_ch_remote_close( { { struct channel_ctx *ctx; struct channel_ctx *ctx; bool is_ch_fully_closed; bool is_ch_fully_closed; struct glink_core_xprt_ctx *xprt_ptr = if_ptr->glink_core_priv; ctx = xprt_rcid_to_ch_ctx_get(if_ptr->glink_core_priv, rcid); ctx = xprt_rcid_to_ch_ctx_get(if_ptr->glink_core_priv, rcid); if (!ctx) { if (!ctx) { Loading @@ -4583,7 +4596,7 @@ static void glink_core_rx_cmd_ch_remote_close( if (is_ch_fully_closed) { if (is_ch_fully_closed) { glink_delete_ch_from_list(ctx, true); glink_delete_ch_from_list(ctx, true); flush_workqueue(ctx->transport_ptr->tx_wq); flush_kthread_worker(&xprt_ptr->tx_wq); } } rwref_put(&ctx->ch_state_lhc0); rwref_put(&ctx->ch_state_lhc0); } } Loading @@ -4599,6 +4612,7 @@ static void glink_core_rx_cmd_ch_close_ack(struct glink_transport_if *if_ptr, { { struct channel_ctx *ctx; struct channel_ctx *ctx; bool is_ch_fully_closed; bool is_ch_fully_closed; struct glink_core_xprt_ctx *xprt_ptr = if_ptr->glink_core_priv; ctx = xprt_lcid_to_ch_ctx_get(if_ptr->glink_core_priv, lcid); ctx = xprt_lcid_to_ch_ctx_get(if_ptr->glink_core_priv, lcid); if (!ctx) { if (!ctx) { Loading @@ -4620,7 +4634,7 @@ static void glink_core_rx_cmd_ch_close_ack(struct glink_transport_if *if_ptr, is_ch_fully_closed = glink_core_ch_close_ack_common(ctx); is_ch_fully_closed = glink_core_ch_close_ack_common(ctx); if (is_ch_fully_closed) { if (is_ch_fully_closed) { glink_delete_ch_from_list(ctx, true); glink_delete_ch_from_list(ctx, true); flush_workqueue(ctx->transport_ptr->tx_wq); flush_kthread_worker(&xprt_ptr->tx_wq); } } rwref_put(&ctx->ch_state_lhc0); rwref_put(&ctx->ch_state_lhc0); } } Loading Loading @@ -4932,8 +4946,7 @@ static void xprt_schedule_tx(struct glink_core_xprt_ctx *xprt_ptr, spin_unlock(&ch_ptr->tx_lists_lock_lhc3); spin_unlock(&ch_ptr->tx_lists_lock_lhc3); spin_unlock_irqrestore(&xprt_ptr->tx_ready_lock_lhb2, flags); spin_unlock_irqrestore(&xprt_ptr->tx_ready_lock_lhb2, flags); queue_kthread_work(&xprt_ptr->tx_wq, &xprt_ptr->tx_kwork); queue_work(xprt_ptr->tx_wq, &xprt_ptr->tx_work); } } /** /** Loading Loading @@ -5114,14 +5127,11 @@ static int glink_scheduler_tx(struct channel_ctx *ctx, return ret; return ret; } } /** * tx_work_func() - Transmit worker /**Actual Transmit function * @work: Linux work structure **/ */ static void tx_func(struct kthread_work *work) static void tx_work_func(struct work_struct *work) { { struct glink_core_xprt_ctx *xprt_ptr = container_of(work, struct glink_core_xprt_ctx, tx_work); struct channel_ctx *ch_ptr; struct channel_ctx *ch_ptr; uint32_t prio; uint32_t prio; uint32_t tx_ready_head_prio; uint32_t tx_ready_head_prio; Loading @@ -5129,6 +5139,8 @@ static void tx_work_func(struct work_struct *work) struct channel_ctx *tx_ready_head = NULL; struct channel_ctx *tx_ready_head = NULL; bool transmitted_successfully = true; bool transmitted_successfully = true; unsigned long flags; unsigned long flags; struct glink_core_xprt_ctx *xprt_ptr = container_of(work, struct glink_core_xprt_ctx, tx_kwork); GLINK_PERF("%s: worker starting\n", __func__); GLINK_PERF("%s: worker starting\n", __func__); Loading Loading @@ -5214,8 +5226,9 @@ static void tx_work_func(struct work_struct *work) static void glink_core_tx_resume(struct glink_transport_if *if_ptr) static void glink_core_tx_resume(struct glink_transport_if *if_ptr) { { queue_work(if_ptr->glink_core_priv->tx_wq, struct glink_core_xprt_ctx *xprt_ptr = if_ptr->glink_core_priv; &if_ptr->glink_core_priv->tx_work); queue_kthread_work(&xprt_ptr->tx_wq, &xprt_ptr->tx_kwork); } } /** /** Loading
drivers/soc/qcom/glink_smd_xprt.c +51 −10 Original line number Original line Diff line number Diff line Loading @@ -10,6 +10,7 @@ * GNU General Public License for more details. * GNU General Public License for more details. */ */ #include <linux/delay.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/list.h> #include <linux/module.h> #include <linux/module.h> Loading Loading @@ -140,6 +141,7 @@ struct channel { uint32_t lcid; uint32_t lcid; uint32_t rcid; uint32_t rcid; struct mutex ch_probe_lock; struct mutex ch_probe_lock; struct mutex ch_tasklet_lock; bool wait_for_probe; bool wait_for_probe; bool had_probed; bool had_probed; struct edge_info *edge; struct edge_info *edge; Loading @@ -149,7 +151,7 @@ struct channel { spinlock_t intents_lock; spinlock_t intents_lock; uint32_t next_intent_id; uint32_t next_intent_id; struct workqueue_struct *wq; struct workqueue_struct *wq; struct work_struct work; struct tasklet_struct data_tasklet; struct intent_info *cur_intent; struct intent_info *cur_intent; bool intent_req; bool intent_req; bool is_closing; bool is_closing; Loading @@ -159,6 +161,7 @@ struct channel { spinlock_t rx_data_lock; spinlock_t rx_data_lock; bool streaming_ch; bool streaming_ch; bool tx_resume_needed; bool tx_resume_needed; bool is_tasklet_enabled; }; }; /** /** Loading Loading @@ -230,7 +233,7 @@ static struct glink_core_version versions[] = { static LIST_HEAD(pdrv_list); static LIST_HEAD(pdrv_list); static DEFINE_MUTEX(pdrv_list_mutex); static DEFINE_MUTEX(pdrv_list_mutex); static void process_data_event(struct work_struct *work); static void process_data_event(unsigned long param); static int add_platform_driver(struct channel *ch); static int add_platform_driver(struct channel *ch); static void smd_data_ch_close(struct channel *ch); static void smd_data_ch_close(struct channel *ch); Loading Loading @@ -324,11 +327,17 @@ static void process_ctl_event(struct work_struct *work) strlcpy(ch->name, name, GLINK_NAME_SIZE); strlcpy(ch->name, name, GLINK_NAME_SIZE); ch->edge = einfo; ch->edge = einfo; mutex_init(&ch->ch_probe_lock); mutex_init(&ch->ch_probe_lock); mutex_init(&ch->ch_tasklet_lock); INIT_LIST_HEAD(&ch->intents); INIT_LIST_HEAD(&ch->intents); INIT_LIST_HEAD(&ch->used_intents); INIT_LIST_HEAD(&ch->used_intents); spin_lock_init(&ch->intents_lock); spin_lock_init(&ch->intents_lock); spin_lock_init(&ch->rx_data_lock); spin_lock_init(&ch->rx_data_lock); INIT_WORK(&ch->work, process_data_event); mutex_lock(&ch->ch_tasklet_lock); tasklet_init(&ch->data_tasklet, process_data_event, (unsigned long)ch); tasklet_disable(&ch->data_tasklet); ch->is_tasklet_enabled = false; mutex_unlock(&ch->ch_tasklet_lock); ch->wq = create_singlethread_workqueue( ch->wq = create_singlethread_workqueue( ch->name); ch->name); if (!ch->wq) { if (!ch->wq) { Loading Loading @@ -362,6 +371,7 @@ static void process_ctl_event(struct work_struct *work) } else { } else { spin_unlock_irqrestore( spin_unlock_irqrestore( &einfo->channels_lock, flags); &einfo->channels_lock, flags); tasklet_kill(&temp_ch->data_tasklet); destroy_workqueue(temp_ch->wq); destroy_workqueue(temp_ch->wq); kfree(temp_ch); kfree(temp_ch); } } Loading Loading @@ -602,6 +612,12 @@ static void process_open_event(struct work_struct *work) SMD_TRANS_XPRT_ID); SMD_TRANS_XPRT_ID); mutex_unlock(&einfo->rx_cmd_lock); mutex_unlock(&einfo->rx_cmd_lock); } } mutex_lock(&ch->ch_tasklet_lock); if (!ch->is_tasklet_enabled) { tasklet_enable(&ch->data_tasklet); ch->is_tasklet_enabled = true; } mutex_unlock(&ch->ch_tasklet_lock); kfree(ch_work); kfree(ch_work); } } Loading @@ -626,6 +642,12 @@ static void process_close_event(struct work_struct *work) ch->rcid); ch->rcid); mutex_unlock(&einfo->rx_cmd_lock); mutex_unlock(&einfo->rx_cmd_lock); } } mutex_lock(&ch->ch_tasklet_lock); if (ch->is_tasklet_enabled) { tasklet_disable(&ch->data_tasklet); ch->is_tasklet_enabled = false; } mutex_unlock(&ch->ch_tasklet_lock); ch->rcid = 0; ch->rcid = 0; } } Loading Loading @@ -696,9 +718,9 @@ static void process_reopen_event(struct work_struct *work) /** /** * process_data_event() - process a data event task * process_data_event() - process a data event task * @work: The data task to process. * @param: Pointer to the channel in long format. */ */ static void process_data_event(struct work_struct *work) static void process_data_event(unsigned long param) { { struct channel *ch; struct channel *ch; struct edge_info *einfo; struct edge_info *einfo; Loading @@ -710,7 +732,7 @@ static void process_data_event(struct work_struct *work) unsigned long intents_flags; unsigned long intents_flags; unsigned long rx_data_flags; unsigned long rx_data_flags; ch = container_of(work, struct channel, work); ch = (struct channel *)param; einfo = ch->edge; einfo = ch->edge; if (ch->tx_resume_needed && smd_write_avail(ch->smd_ch) > 0) { if (ch->tx_resume_needed && smd_write_avail(ch->smd_ch) > 0) { Loading Loading @@ -810,7 +832,7 @@ static void smd_data_ch_notify(void *priv, unsigned event) switch (event) { switch (event) { case SMD_EVENT_DATA: case SMD_EVENT_DATA: queue_work(ch->wq, &ch->work); tasklet_hi_schedule(&ch->data_tasklet); break; break; case SMD_EVENT_OPEN: case SMD_EVENT_OPEN: work = kmalloc(sizeof(*work), GFP_ATOMIC); work = kmalloc(sizeof(*work), GFP_ATOMIC); Loading Loading @@ -883,6 +905,12 @@ static void smd_data_ch_close(struct channel *ch) ch->is_closing = true; ch->is_closing = true; ch->tx_resume_needed = false; ch->tx_resume_needed = false; mutex_lock(&ch->ch_tasklet_lock); if (ch->is_tasklet_enabled) { tasklet_disable(&ch->data_tasklet); ch->is_tasklet_enabled = false; } mutex_unlock(&ch->ch_tasklet_lock); flush_workqueue(ch->wq); flush_workqueue(ch->wq); mutex_lock(&ch->ch_probe_lock); mutex_lock(&ch->ch_probe_lock); Loading Loading @@ -1186,11 +1214,17 @@ static int tx_cmd_ch_open(struct glink_transport_if *if_ptr, uint32_t lcid, strlcpy(ch->name, name, GLINK_NAME_SIZE); strlcpy(ch->name, name, GLINK_NAME_SIZE); ch->edge = einfo; ch->edge = einfo; mutex_init(&ch->ch_probe_lock); mutex_init(&ch->ch_probe_lock); mutex_init(&ch->ch_tasklet_lock); INIT_LIST_HEAD(&ch->intents); INIT_LIST_HEAD(&ch->intents); INIT_LIST_HEAD(&ch->used_intents); INIT_LIST_HEAD(&ch->used_intents); spin_lock_init(&ch->intents_lock); spin_lock_init(&ch->intents_lock); spin_lock_init(&ch->rx_data_lock); spin_lock_init(&ch->rx_data_lock); INIT_WORK(&ch->work, process_data_event); mutex_lock(&ch->ch_tasklet_lock); tasklet_init(&ch->data_tasklet, process_data_event, (unsigned long)ch); tasklet_disable(&ch->data_tasklet); ch->is_tasklet_enabled = false; mutex_unlock(&ch->ch_tasklet_lock); ch->wq = create_singlethread_workqueue(ch->name); ch->wq = create_singlethread_workqueue(ch->name); if (!ch->wq) { if (!ch->wq) { SMDXPRT_ERR(einfo, SMDXPRT_ERR(einfo, Loading Loading @@ -1220,6 +1254,7 @@ static int tx_cmd_ch_open(struct glink_transport_if *if_ptr, uint32_t lcid, spin_unlock_irqrestore(&einfo->channels_lock, flags); spin_unlock_irqrestore(&einfo->channels_lock, flags); } else { } else { spin_unlock_irqrestore(&einfo->channels_lock, flags); spin_unlock_irqrestore(&einfo->channels_lock, flags); tasklet_kill(&temp_ch->data_tasklet); destroy_workqueue(temp_ch->wq); destroy_workqueue(temp_ch->wq); kfree(temp_ch); kfree(temp_ch); } } Loading Loading @@ -1463,6 +1498,12 @@ static int ssr(struct glink_transport_if *if_ptr) list_for_each_entry(ch, &einfo->channels, node) { list_for_each_entry(ch, &einfo->channels, node) { spin_unlock_irqrestore(&einfo->channels_lock, flags); spin_unlock_irqrestore(&einfo->channels_lock, flags); ch->is_closing = true; ch->is_closing = true; mutex_lock(&ch->ch_tasklet_lock); if (ch->is_tasklet_enabled) { tasklet_disable(&ch->data_tasklet); ch->is_tasklet_enabled = false; } mutex_unlock(&ch->ch_tasklet_lock); flush_workqueue(ch->wq); flush_workqueue(ch->wq); mutex_lock(&ch->ch_probe_lock); mutex_lock(&ch->ch_probe_lock); ch->wait_for_probe = false; ch->wait_for_probe = false; Loading Loading @@ -1568,7 +1609,7 @@ static void check_and_resume_rx(struct channel *ch, size_t intent_size) { { if (ch->intent_req && ch->intent_req_size <= intent_size) { if (ch->intent_req && ch->intent_req_size <= intent_size) { ch->intent_req = false; ch->intent_req = false; queue_work(ch->wq, &ch->work); tasklet_hi_schedule(&ch->data_tasklet); } } } } Loading Loading @@ -1895,7 +1936,7 @@ static int poll(struct glink_transport_if *if_ptr, uint32_t lcid) spin_unlock_irqrestore(&einfo->channels_lock, flags); spin_unlock_irqrestore(&einfo->channels_lock, flags); rc = smd_is_pkt_avail(ch->smd_ch); rc = smd_is_pkt_avail(ch->smd_ch); if (rc == 1) if (rc == 1) process_data_event(&ch->work); process_data_event((unsigned long)ch); return rc; return rc; } } Loading
drivers/soc/qcom/glink_smem_native_xprt.c +24 −2 Original line number Original line Diff line number Diff line Loading @@ -169,7 +169,10 @@ struct mailbox_config_info { * been sent, and a response is pending from the * been sent, and a response is pending from the * remote side. Protected by @write_lock. * remote side. Protected by @write_lock. * @kwork: Work to be executed when an irq is received. * @kwork: Work to be executed when an irq is received. * @kworker: Handle to the entity processing @kwork. * @kworker: Handle to the entity processing of deferred commands. * @tasklet Handle to tasklet to process incoming data packets in atomic manner. * @task: Handle to the task context used to run @kworker. * @task: Handle to the task context used to run @kworker. * @use_ref: Active uses of this transport use this to grab * @use_ref: Active uses of this transport use this to grab * a reference. Used for ssr synchronization. * a reference. Used for ssr synchronization. Loading Loading @@ -210,6 +213,7 @@ struct edge_info { struct kthread_work kwork; struct kthread_work kwork; struct kthread_worker kworker; struct kthread_worker kworker; struct task_struct *task; struct task_struct *task; struct tasklet_struct tasklet; struct srcu_struct use_ref; struct srcu_struct use_ref; bool in_ssr; bool in_ssr; spinlock_t rx_lock; spinlock_t rx_lock; Loading Loading @@ -1144,6 +1148,18 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) srcu_read_unlock(&einfo->use_ref, rcu_id); srcu_read_unlock(&einfo->use_ref, rcu_id); } } /** * rx_worker_atomic() - worker function to process received command in atomic * context. * @param: The param parameter passed during initialization of the tasklet. */ static void rx_worker_atomic(unsigned long param) { struct edge_info *einfo = (struct edge_info *)param; __rx_worker(einfo, true); } /** /** * rx_worker() - worker function to process received commands * rx_worker() - worker function to process received commands * @work: kwork associated with the edge to process commands on. * @work: kwork associated with the edge to process commands on. Loading @@ -1163,7 +1179,7 @@ irqreturn_t irq_handler(int irq, void *priv) if (einfo->rx_reset_reg) if (einfo->rx_reset_reg) writel_relaxed(einfo->out_irq_mask, einfo->rx_reset_reg); writel_relaxed(einfo->out_irq_mask, einfo->rx_reset_reg); queue_kthread_work(&einfo->kworker, &einfo->kwork); tasklet_hi_schedule(&einfo->tasklet); einfo->rx_irq_count++; einfo->rx_irq_count++; return IRQ_HANDLED; return IRQ_HANDLED; Loading Loading @@ -2244,6 +2260,7 @@ static int glink_smem_native_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); init_waitqueue_head(&einfo->tx_blocked_queue); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_worker(&einfo->kworker); init_kthread_worker(&einfo->kworker); tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->read_from_fifo = read_from_fifo; einfo->read_from_fifo = read_from_fifo; einfo->write_to_fifo = write_to_fifo; einfo->write_to_fifo = write_to_fifo; init_srcu_struct(&einfo->use_ref); init_srcu_struct(&einfo->use_ref); Loading Loading @@ -2344,6 +2361,7 @@ smem_alloc_fail: flush_kthread_worker(&einfo->kworker); flush_kthread_worker(&einfo->kworker); kthread_stop(einfo->task); kthread_stop(einfo->task); einfo->task = NULL; einfo->task = NULL; tasklet_kill(&einfo->tasklet); kthread_fail: kthread_fail: iounmap(einfo->out_irq_reg); iounmap(einfo->out_irq_reg); ioremap_fail: ioremap_fail: Loading Loading @@ -2429,6 +2447,7 @@ static int glink_rpm_native_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); init_waitqueue_head(&einfo->tx_blocked_queue); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_worker(&einfo->kworker); init_kthread_worker(&einfo->kworker); tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->intentless = true; einfo->intentless = true; einfo->read_from_fifo = memcpy32_fromio; einfo->read_from_fifo = memcpy32_fromio; einfo->write_to_fifo = memcpy32_toio; einfo->write_to_fifo = memcpy32_toio; Loading Loading @@ -2590,6 +2609,7 @@ toc_init_fail: flush_kthread_worker(&einfo->kworker); flush_kthread_worker(&einfo->kworker); kthread_stop(einfo->task); kthread_stop(einfo->task); einfo->task = NULL; einfo->task = NULL; tasklet_kill(&einfo->tasklet); kthread_fail: kthread_fail: iounmap(msgram); iounmap(msgram); msgram_ioremap_fail: msgram_ioremap_fail: Loading Loading @@ -2718,6 +2738,7 @@ static int glink_mailbox_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); init_waitqueue_head(&einfo->tx_blocked_queue); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_work(&einfo->kwork, rx_worker); init_kthread_worker(&einfo->kworker); init_kthread_worker(&einfo->kworker); tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->read_from_fifo = read_from_fifo; einfo->read_from_fifo = read_from_fifo; einfo->write_to_fifo = write_to_fifo; einfo->write_to_fifo = write_to_fifo; init_srcu_struct(&einfo->use_ref); init_srcu_struct(&einfo->use_ref); Loading Loading @@ -2839,6 +2860,7 @@ smem_alloc_fail: flush_kthread_worker(&einfo->kworker); flush_kthread_worker(&einfo->kworker); kthread_stop(einfo->task); kthread_stop(einfo->task); einfo->task = NULL; einfo->task = NULL; tasklet_kill(&einfo->tasklet); kthread_fail: kthread_fail: iounmap(einfo->rx_reset_reg); iounmap(einfo->rx_reset_reg); rx_reset_ioremap_fail: rx_reset_ioremap_fail: Loading