summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSujeev Dias <sdias@codeaurora.org>2017-01-11 19:46:17 -0800
committerSujeev Dias <sdias@codeaurora.org>2017-03-11 13:26:48 -0800
commit65d8df7619ff26339014247bfe62916d9e38882f (patch)
treea91a6d3eb1acfaddeac2ebbe4326d10b469b4917
parent41fb6e92abab37b865bcdb77960dea1521832f42 (diff)
mhi: core: add support for priority based event processing
Not all events require same priority to process. Process high priority events using a tasklet while processing low priority events using a kworker. Priority for events can be configured by device tree. CRs-Fixed: 2004759 Change-Id: I6bf04624c2fd92afd7c698d6a57f66619ea13b5b Signed-off-by: Sujeev Dias <sdias@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/mhi/msm_mhi.txt7
-rw-r--r--drivers/platform/msm/mhi/mhi.h31
-rw-r--r--drivers/platform/msm/mhi/mhi_event.c26
-rw-r--r--drivers/platform/msm/mhi/mhi_iface.c6
-rw-r--r--drivers/platform/msm/mhi/mhi_init.c48
-rw-r--r--drivers/platform/msm/mhi/mhi_isr.c126
-rw-r--r--drivers/platform/msm/mhi/mhi_main.c3
-rw-r--r--drivers/platform/msm/mhi/mhi_states.c107
8 files changed, 106 insertions, 248 deletions
diff --git a/Documentation/devicetree/bindings/mhi/msm_mhi.txt b/Documentation/devicetree/bindings/mhi/msm_mhi.txt
index 6467f4d103e5..5f950604d186 100644
--- a/Documentation/devicetree/bindings/mhi/msm_mhi.txt
+++ b/Documentation/devicetree/bindings/mhi/msm_mhi.txt
@@ -88,12 +88,13 @@ Main node properties:
Usage: required
Value type: Array of <u32>
Definition: mhi event ring configuration parameters for platform
- defined as below <A B C D E>:
+ defined as below <A B C D E F>:
A = maximum event descriptors
B = MSI associated with event
C = interrupt moderation (see MHI specification)
D = Associated channel
- E = flags defined by mhi_macros.h GET_EV_PROPS
+ E = priority of the event ring. 0 being the highest.
+ F = flags defined by mhi_macros.h GET_EV_PROPS
- qcom,mhi-address-window
Usage: required
@@ -147,5 +148,5 @@ mhi: qcom,mhi {
<100 512 1200000000 1200000000>;
mhi-event-rings = <1>;
mhi-chan-cfg-102 = <0x66 0x80 0x5 0x62>;
- mhi-event-cfg-0 = <0x80 0x0 0x0 0x0 0x11>;
+ mhi-event-cfg-0 = <0x80 0x0 0x0 0x0 0 1 0x11>;
};
diff --git a/drivers/platform/msm/mhi/mhi.h b/drivers/platform/msm/mhi/mhi.h
index de46fd39259a..4bce96102525 100644
--- a/drivers/platform/msm/mhi/mhi.h
+++ b/drivers/platform/msm/mhi/mhi.h
@@ -349,6 +349,10 @@ struct mhi_ring {
u32 msi_enable_cntr;
spinlock_t ring_lock;
struct dma_pool *dma_pool;
+ struct tasklet_struct ev_task;
+ struct work_struct ev_worker;
+ struct mhi_device_ctxt *mhi_dev_ctxt;
+ int index;
};
enum MHI_CMD_STATUS {
@@ -469,7 +473,6 @@ struct mhi_counters {
u32 bb_used[MHI_MAX_CHANNELS];
atomic_t device_wake;
atomic_t outbound_acks;
- atomic_t events_pending;
u32 *msi_counter;
u32 mhi_reset_cntr;
u32 link_down_cntr;
@@ -479,16 +482,10 @@ struct mhi_counters {
struct mhi_flags {
u32 mhi_initialized;
u32 link_up;
- int stop_threads;
- u32 kill_threads;
- u32 ev_thread_stopped;
- u32 st_thread_stopped;
bool bb_required;
};
struct mhi_wait_queues {
- wait_queue_head_t *mhi_event_wq;
- wait_queue_head_t *state_change_event;
wait_queue_head_t *m0_event;
wait_queue_head_t *m3_event;
wait_queue_head_t *bhi_event;
@@ -547,9 +544,7 @@ struct mhi_device_ctxt {
struct mhi_client_handle *client_handle_list[MHI_MAX_CHANNELS];
struct mhi_event_ring_cfg *ev_ring_props;
- struct task_struct *event_thread_handle;
- struct task_struct *st_thread_handle;
- struct tasklet_struct ev_task; /* Process control Events */
+ struct work_struct st_thread_worker;
struct work_struct process_m1_worker;
struct mhi_wait_queues mhi_ev_wq;
struct dev_mmio_info mmio_info;
@@ -609,10 +604,18 @@ struct mhi_event_ring_cfg {
u32 intmod;
enum MHI_CLIENT_CHANNEL chan;
u32 flags;
+ /*
+ * Priority of event handling:
+ * 0 = highest, handle events in isr (reserved for future)
+ * 1 = handles event using tasklet
+ * 2 = handles events using workerthread
+ */
+ u32 priority;
enum MHI_RING_CLASS class;
enum MHI_EVENT_RING_STATE state;
irqreturn_t (*mhi_handler_ptr)(int , void *);
};
+#define MHI_EV_PRIORITY_TASKLET (1)
struct mhi_data_buf {
dma_addr_t bounce_buffer;
@@ -670,14 +673,13 @@ enum MHI_EVENT_CCS get_cmd_pkt(struct mhi_device_ctxt *mhi_dev_ctxt,
union mhi_cmd_pkt **cmd_pkt, u32 event_index);
int parse_cmd_event(struct mhi_device_ctxt *ctxt,
union mhi_event_pkt *event, u32 event_index);
-int parse_event_thread(void *ctxt);
int mhi_test_for_device_ready(
struct mhi_device_ctxt *mhi_dev_ctxt);
int mhi_test_for_device_reset(
struct mhi_device_ctxt *mhi_dev_ctxt);
int validate_ring_el_addr(struct mhi_ring *ring, uintptr_t addr);
int validate_ev_el_addr(struct mhi_ring *ring, uintptr_t addr);
-int mhi_state_change_thread(void *ctxt);
+void mhi_state_change_worker(struct work_struct *work);
int mhi_init_state_transition(struct mhi_device_ctxt *mhi_dev_ctxt,
enum STATE_TRANSITION new_state);
int mhi_wait_for_mdm(struct mhi_device_ctxt *mhi_dev_ctxt);
@@ -751,6 +753,9 @@ int set_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt);
void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt,
enum MHI_STATE new_state);
const char *state_transition_str(enum STATE_TRANSITION state);
-void mhi_ctrl_ev_task(unsigned long data);
+void mhi_ev_task(unsigned long data);
+void process_event_ring(struct work_struct *work);
+int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt);
+int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt);
#endif
diff --git a/drivers/platform/msm/mhi/mhi_event.c b/drivers/platform/msm/mhi/mhi_event.c
index 3103ade8c8d4..ae677bae63dc 100644
--- a/drivers/platform/msm/mhi/mhi_event.c
+++ b/drivers/platform/msm/mhi/mhi_event.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* 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
@@ -43,13 +43,13 @@ int mhi_populate_event_cfg(struct mhi_device_ctxt *mhi_dev_ctxt)
return -ENOMEM;
for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; ++i) {
- u32 dt_configs[5];
- int len;
+ u32 dt_configs[6];
+ int no_elements;
scnprintf(dt_prop, MAX_BUF_SIZE, "%s%d", "mhi-event-cfg-", i);
- if (!of_find_property(np, dt_prop, &len))
- goto dt_error;
- if (len != sizeof(dt_configs))
+ no_elements = of_property_count_elems_of_size(np, dt_prop,
+ sizeof(dt_configs));
+ if (no_elements != 1)
goto dt_error;
r = of_property_read_u32_array(
np,
@@ -66,14 +66,16 @@ int mhi_populate_event_cfg(struct mhi_device_ctxt *mhi_dev_ctxt)
mhi_dev_ctxt->ev_ring_props[i].msi_vec = dt_configs[1];
mhi_dev_ctxt->ev_ring_props[i].intmod = dt_configs[2];
mhi_dev_ctxt->ev_ring_props[i].chan = dt_configs[3];
- mhi_dev_ctxt->ev_ring_props[i].flags = dt_configs[4];
+ mhi_dev_ctxt->ev_ring_props[i].priority = dt_configs[4];
+ mhi_dev_ctxt->ev_ring_props[i].flags = dt_configs[5];
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "ev ring %d,desc:0x%x,msi:0x%x,intmod%d chan:%u flags0x%x\n",
+ "ev ring %d,desc:0x%x,msi:0x%x,intmod%d chan:%u priority:%u flags0x%x\n",
i,
mhi_dev_ctxt->ev_ring_props[i].nr_desc,
mhi_dev_ctxt->ev_ring_props[i].msi_vec,
mhi_dev_ctxt->ev_ring_props[i].intmod,
mhi_dev_ctxt->ev_ring_props[i].chan,
+ mhi_dev_ctxt->ev_ring_props[i].priority,
mhi_dev_ctxt->ev_ring_props[i].flags);
if (GET_EV_PROPS(EV_MANAGED,
mhi_dev_ctxt->ev_ring_props[i].flags))
@@ -128,6 +130,9 @@ int create_local_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt)
mhi_local_event_ctxt[i];
spin_lock_init(&mhi_ring->ring_lock);
+ tasklet_init(&mhi_ring->ev_task, mhi_ev_task,
+ (unsigned long)mhi_ring);
+ INIT_WORK(&mhi_ring->ev_worker, process_event_ring);
}
return r;
@@ -157,6 +162,8 @@ void ring_ev_db(struct mhi_device_ctxt *mhi_dev_ctxt, u32 event_ring_index)
static int mhi_event_ring_init(struct mhi_event_ctxt *ev_list,
struct mhi_ring *ring,
+ struct mhi_device_ctxt *mhi_dev_ctxt,
+ int index,
u32 el_per_ring,
u32 intmodt_val,
u32 msi_vec,
@@ -166,6 +173,8 @@ static int mhi_event_ring_init(struct mhi_event_ctxt *ev_list,
ev_list->mhi_msi_vector = msi_vec;
ev_list->mhi_event_ring_len = el_per_ring*sizeof(union mhi_event_pkt);
MHI_SET_EV_CTXT(EVENT_CTXT_INTMODT, ev_list, intmodt_val);
+ ring->mhi_dev_ctxt = mhi_dev_ctxt;
+ ring->index = index;
ring->len = ((size_t)(el_per_ring)*sizeof(union mhi_event_pkt));
ring->el_size = sizeof(union mhi_event_pkt);
ring->overwrite_en = 0;
@@ -198,6 +207,7 @@ void init_event_ctxt_array(struct mhi_device_ctxt *mhi_dev_ctxt)
event_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[i];
mhi_local_event_ctxt = &mhi_dev_ctxt->mhi_local_event_ctxt[i];
mhi_event_ring_init(event_ctxt, mhi_local_event_ctxt,
+ mhi_dev_ctxt, i,
mhi_dev_ctxt->ev_ring_props[i].nr_desc,
mhi_dev_ctxt->ev_ring_props[i].intmod,
mhi_dev_ctxt->ev_ring_props[i].msi_vec,
diff --git a/drivers/platform/msm/mhi/mhi_iface.c b/drivers/platform/msm/mhi/mhi_iface.c
index 50e330a6742b..4dacc33b386e 100644
--- a/drivers/platform/msm/mhi/mhi_iface.c
+++ b/drivers/platform/msm/mhi/mhi_iface.c
@@ -110,8 +110,6 @@ int mhi_ctxt_init(struct mhi_device_ctxt *mhi_dev_ctxt)
irq_error:
kfree(mhi_dev_ctxt->state_change_work_item_list.q_lock);
- kfree(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq);
- kfree(mhi_dev_ctxt->mhi_ev_wq.state_change_event);
kfree(mhi_dev_ctxt->mhi_ev_wq.m0_event);
kfree(mhi_dev_ctxt->mhi_ev_wq.m3_event);
kfree(mhi_dev_ctxt->mhi_ev_wq.bhi_event);
@@ -190,12 +188,10 @@ static int mhi_pci_probe(struct pci_dev *pcie_device,
pcie_device->dev.of_node = plat_dev->dev.of_node;
mhi_dev_ctxt->mhi_pm_state = MHI_PM_DISABLE;
INIT_WORK(&mhi_dev_ctxt->process_m1_worker, process_m1_transition);
+ INIT_WORK(&mhi_dev_ctxt->st_thread_worker, mhi_state_change_worker);
mutex_init(&mhi_dev_ctxt->pm_lock);
rwlock_init(&mhi_dev_ctxt->pm_xfer_lock);
spin_lock_init(&mhi_dev_ctxt->dev_wake_lock);
- tasklet_init(&mhi_dev_ctxt->ev_task,
- mhi_ctrl_ev_task,
- (unsigned long)mhi_dev_ctxt);
init_completion(&mhi_dev_ctxt->cmd_complete);
mhi_dev_ctxt->flags.link_up = 1;
diff --git a/drivers/platform/msm/mhi/mhi_init.c b/drivers/platform/msm/mhi/mhi_init.c
index e6bf75d9d7e7..b6edf707798b 100644
--- a/drivers/platform/msm/mhi/mhi_init.c
+++ b/drivers/platform/msm/mhi/mhi_init.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* 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
@@ -250,19 +250,6 @@ err_ev_alloc:
static int mhi_init_events(struct mhi_device_ctxt *mhi_dev_ctxt)
{
- mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq = kmalloc(
- sizeof(wait_queue_head_t),
- GFP_KERNEL);
- if (NULL == mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to init event");
- return -ENOMEM;
- }
- mhi_dev_ctxt->mhi_ev_wq.state_change_event =
- kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
- if (NULL == mhi_dev_ctxt->mhi_ev_wq.state_change_event) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to init event");
- goto error_event_handle_alloc;
- }
/* Initialize the event which signals M0 */
mhi_dev_ctxt->mhi_ev_wq.m0_event = kmalloc(sizeof(wait_queue_head_t),
GFP_KERNEL);
@@ -284,10 +271,7 @@ static int mhi_init_events(struct mhi_device_ctxt *mhi_dev_ctxt)
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to init event");
goto error_bhi_event;
}
- /* Initialize the event which starts the event parsing thread */
- init_waitqueue_head(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq);
- /* Initialize the event which starts the state change thread */
- init_waitqueue_head(mhi_dev_ctxt->mhi_ev_wq.state_change_event);
+
/* Initialize the event which triggers clients waiting to send */
init_waitqueue_head(mhi_dev_ctxt->mhi_ev_wq.m0_event);
/* Initialize the event which triggers D3hot */
@@ -300,9 +284,6 @@ error_bhi_event:
error_m0_event:
kfree(mhi_dev_ctxt->mhi_ev_wq.m0_event);
error_state_change_event_handle:
- kfree(mhi_dev_ctxt->mhi_ev_wq.state_change_event);
-error_event_handle_alloc:
- kfree(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq);
return -ENOMEM;
}
@@ -339,21 +320,6 @@ static void mhi_init_wakelock(struct mhi_device_ctxt *mhi_dev_ctxt)
wakeup_source_init(&mhi_dev_ctxt->w_lock, "mhi_wakeup_source");
}
-static int mhi_spawn_threads(struct mhi_device_ctxt *mhi_dev_ctxt)
-{
- mhi_dev_ctxt->event_thread_handle = kthread_run(parse_event_thread,
- mhi_dev_ctxt,
- "mhi_ev_thrd");
- if (IS_ERR(mhi_dev_ctxt->event_thread_handle))
- return PTR_ERR(mhi_dev_ctxt->event_thread_handle);
- mhi_dev_ctxt->st_thread_handle = kthread_run(mhi_state_change_thread,
- mhi_dev_ctxt,
- "mhi_st_thrd");
- if (IS_ERR(mhi_dev_ctxt->event_thread_handle))
- return PTR_ERR(mhi_dev_ctxt->event_thread_handle);
- return 0;
-}
-
/**
* @brief Main initialization function for a mhi struct device context
* All threads, events mutexes, mhi specific data structures
@@ -408,21 +374,11 @@ int mhi_init_device_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt)
init_event_ctxt_array(mhi_dev_ctxt);
mhi_dev_ctxt->mhi_state = MHI_STATE_RESET;
- r = mhi_spawn_threads(mhi_dev_ctxt);
- if (r) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "Failed to spawn threads ret %d\n", r);
- goto error_during_thread_spawn;
- }
mhi_init_wakelock(mhi_dev_ctxt);
return r;
-error_during_thread_spawn:
- kfree(mhi_dev_ctxt->state_change_work_item_list.q_lock);
error_during_thread_init:
- kfree(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq);
- kfree(mhi_dev_ctxt->mhi_ev_wq.state_change_event);
kfree(mhi_dev_ctxt->mhi_ev_wq.m0_event);
kfree(mhi_dev_ctxt->mhi_ev_wq.m3_event);
kfree(mhi_dev_ctxt->mhi_ev_wq.bhi_event);
diff --git a/drivers/platform/msm/mhi/mhi_isr.c b/drivers/platform/msm/mhi/mhi_isr.c
index 5bd0dcf300d7..95efe62eb8d4 100644
--- a/drivers/platform/msm/mhi/mhi_isr.c
+++ b/drivers/platform/msm/mhi/mhi_isr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* 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
@@ -125,8 +125,11 @@ static int mhi_process_event_ring(
"MHI STE received ring 0x%x State:%s\n",
ev_index, state_transition_str(new_state));
- /* If transitioning to M1 schedule worker thread */
- if (new_state == STATE_TRANSITION_M1) {
+ switch (new_state) {
+ case STATE_TRANSITION_M0:
+ process_m0_transition(mhi_dev_ctxt);
+ break;
+ case STATE_TRANSITION_M1:
write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock,
flags);
mhi_dev_ctxt->mhi_state =
@@ -140,9 +143,15 @@ static int mhi_process_event_ring(
write_unlock_irqrestore(&mhi_dev_ctxt->
pm_xfer_lock,
flags);
- } else {
- mhi_init_state_transition(mhi_dev_ctxt,
- new_state);
+ break;
+ case STATE_TRANSITION_M3:
+ process_m3_transition(mhi_dev_ctxt);
+ break;
+ default:
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Unsupported STE received ring 0x%x State:%s\n",
+ ev_index,
+ state_transition_str(new_state));
}
break;
}
@@ -207,84 +216,39 @@ static int mhi_process_event_ring(
return ret_val;
}
-int parse_event_thread(void *ctxt)
+void mhi_ev_task(unsigned long data)
{
- struct mhi_device_ctxt *mhi_dev_ctxt = ctxt;
- u32 i = 0;
- int ret_val = 0;
- int ret_val_process_event = 0;
- atomic_t *ev_pen_ptr = &mhi_dev_ctxt->counters.events_pending;
+ struct mhi_ring *mhi_ring = (struct mhi_ring *)data;
+ struct mhi_device_ctxt *mhi_dev_ctxt =
+ mhi_ring->mhi_dev_ctxt;
+ int ev_index = mhi_ring->index;
+ struct mhi_event_ring_cfg *ring_props =
+ &mhi_dev_ctxt->ev_ring_props[ev_index];
- /* Go through all event rings */
- for (;;) {
- ret_val =
- wait_event_interruptible(
- *mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq,
- ((atomic_read(
- &mhi_dev_ctxt->counters.events_pending) > 0) &&
- !mhi_dev_ctxt->flags.stop_threads) ||
- mhi_dev_ctxt->flags.kill_threads ||
- (mhi_dev_ctxt->flags.stop_threads &&
- !mhi_dev_ctxt->flags.ev_thread_stopped));
+ mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Enter\n");
+ /* Process event ring */
+ mhi_process_event_ring(mhi_dev_ctxt, ev_index, ring_props->nr_desc);
- switch (ret_val) {
- case -ERESTARTSYS:
- return 0;
- default:
- if (mhi_dev_ctxt->flags.kill_threads) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Caught exit signal, quitting\n");
- return 0;
- }
- if (mhi_dev_ctxt->flags.stop_threads) {
- mhi_dev_ctxt->flags.ev_thread_stopped = 1;
- continue;
- }
- break;
- }
- mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "awake\n");
- mhi_dev_ctxt->flags.ev_thread_stopped = 0;
- atomic_dec(&mhi_dev_ctxt->counters.events_pending);
- for (i = 1; i < mhi_dev_ctxt->mmio_info.nr_event_rings; ++i) {
- if (mhi_dev_ctxt->mhi_state == MHI_STATE_SYS_ERR) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "SYS_ERR detected, not processing events\n");
- atomic_set(&mhi_dev_ctxt->
- counters.events_pending,
- 0);
- break;
- }
- if (GET_EV_PROPS(EV_MANAGED,
- mhi_dev_ctxt->ev_ring_props[i].flags)) {
- ret_val_process_event =
- mhi_process_event_ring(mhi_dev_ctxt,
- i,
- mhi_dev_ctxt->
- ev_ring_props[i].nr_desc);
- if (ret_val_process_event == -EINPROGRESS)
- atomic_inc(ev_pen_ptr);
- }
- }
- mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "sleep\n");
- }
+ enable_irq(MSI_TO_IRQ(mhi_dev_ctxt, ev_index));
+ mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Exit\n");
}
-void mhi_ctrl_ev_task(unsigned long data)
+void process_event_ring(struct work_struct *work)
{
+ struct mhi_ring *mhi_ring =
+ container_of(work, struct mhi_ring, ev_worker);
struct mhi_device_ctxt *mhi_dev_ctxt =
- (struct mhi_device_ctxt *)data;
- const unsigned CTRL_EV_RING = 0;
+ mhi_ring->mhi_dev_ctxt;
+ int ev_index = mhi_ring->index;
struct mhi_event_ring_cfg *ring_props =
- &mhi_dev_ctxt->ev_ring_props[CTRL_EV_RING];
+ &mhi_dev_ctxt->ev_ring_props[ev_index];
mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Enter\n");
- /* Process control event ring */
- mhi_process_event_ring(mhi_dev_ctxt,
- CTRL_EV_RING,
- ring_props->nr_desc);
- enable_irq(MSI_TO_IRQ(mhi_dev_ctxt, CTRL_EV_RING));
- mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Exit\n");
+ /* Process event ring */
+ mhi_process_event_ring(mhi_dev_ctxt, ev_index, ring_props->nr_desc);
+ enable_irq(MSI_TO_IRQ(mhi_dev_ctxt, ev_index));
+ mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Exit\n");
}
struct mhi_result *mhi_poll(struct mhi_client_handle *client_handle)
@@ -332,19 +296,19 @@ irqreturn_t mhi_msi_handlr(int irq_number, void *dev_id)
{
struct mhi_device_ctxt *mhi_dev_ctxt = dev_id;
int msi = IRQ_TO_MSI(mhi_dev_ctxt, irq_number);
+ struct mhi_ring *mhi_ring = &mhi_dev_ctxt->mhi_local_event_ctxt[msi];
+ struct mhi_event_ring_cfg *ring_props =
+ &mhi_dev_ctxt->ev_ring_props[msi];
mhi_dev_ctxt->counters.msi_counter[
IRQ_TO_MSI(mhi_dev_ctxt, irq_number)]++;
mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Got MSI 0x%x\n", msi);
trace_mhi_msi(IRQ_TO_MSI(mhi_dev_ctxt, irq_number));
-
- if (msi) {
- atomic_inc(&mhi_dev_ctxt->counters.events_pending);
- wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq);
- } else {
- disable_irq_nosync(irq_number);
- tasklet_schedule(&mhi_dev_ctxt->ev_task);
- }
+ disable_irq_nosync(irq_number);
+ if (ring_props->priority <= MHI_EV_PRIORITY_TASKLET)
+ tasklet_schedule(&mhi_ring->ev_task);
+ else
+ schedule_work(&mhi_ring->ev_worker);
return IRQ_HANDLED;
}
diff --git a/drivers/platform/msm/mhi/mhi_main.c b/drivers/platform/msm/mhi/mhi_main.c
index 889c4708692e..66d56bdd8f85 100644
--- a/drivers/platform/msm/mhi/mhi_main.c
+++ b/drivers/platform/msm/mhi/mhi_main.c
@@ -1788,11 +1788,10 @@ int mhi_register_device(struct mhi_device *mhi_device,
mhi_dev_ctxt->pcie_device = pci_dev;
mhi_dev_ctxt->mhi_pm_state = MHI_PM_DISABLE;
INIT_WORK(&mhi_dev_ctxt->process_m1_worker, process_m1_transition);
+ INIT_WORK(&mhi_dev_ctxt->st_thread_worker, mhi_state_change_worker);
mutex_init(&mhi_dev_ctxt->pm_lock);
rwlock_init(&mhi_dev_ctxt->pm_xfer_lock);
spin_lock_init(&mhi_dev_ctxt->dev_wake_lock);
- tasklet_init(&mhi_dev_ctxt->ev_task, mhi_ctrl_ev_task,
- (unsigned long)mhi_dev_ctxt);
init_completion(&mhi_dev_ctxt->cmd_complete);
mhi_dev_ctxt->flags.link_up = 1;
core_info = &mhi_dev_ctxt->core;
diff --git a/drivers/platform/msm/mhi/mhi_states.c b/drivers/platform/msm/mhi/mhi_states.c
index 707c5b3b7dbc..a4da6c21b50d 100644
--- a/drivers/platform/msm/mhi/mhi_states.c
+++ b/drivers/platform/msm/mhi/mhi_states.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* 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
@@ -169,10 +169,9 @@ static int process_bhie_transition(struct mhi_device_ctxt *mhi_dev_ctxt,
return 0;
}
-static int process_m0_transition(
- struct mhi_device_ctxt *mhi_dev_ctxt,
- enum STATE_TRANSITION cur_work_item)
+int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt)
{
+ unsigned long flags;
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Entered With State %s\n",
@@ -189,10 +188,10 @@ static int process_m0_transition(
break;
}
- write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags);
mhi_dev_ctxt->mhi_state = MHI_STATE_M0;
mhi_dev_ctxt->mhi_pm_state = MHI_PM_M0;
- write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags);
read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock);
mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, true);
@@ -266,11 +265,9 @@ void process_m1_transition(struct work_struct *work)
mutex_unlock(&mhi_dev_ctxt->pm_lock);
}
-static int process_m3_transition(
- struct mhi_device_ctxt *mhi_dev_ctxt,
- enum STATE_TRANSITION cur_work_item)
+int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt)
{
-
+ unsigned long flags;
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Entered with State %s\n",
TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
@@ -286,34 +283,14 @@ static int process_m3_transition(
break;
}
- write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags);
mhi_dev_ctxt->mhi_state = MHI_STATE_M3;
mhi_dev_ctxt->mhi_pm_state = MHI_PM_M3;
- write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags);
wake_up(mhi_dev_ctxt->mhi_ev_wq.m3_event);
return 0;
}
-static int process_link_down_transition(
- struct mhi_device_ctxt *mhi_dev_ctxt,
- enum STATE_TRANSITION cur_work_item)
-{
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Entered with State %s\n",
- TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
- return -EIO;
-}
-
-static int process_wake_transition(
- struct mhi_device_ctxt *mhi_dev_ctxt,
- enum STATE_TRANSITION cur_work_item)
-{
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Entered with State %s\n",
- TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
- return -EIO;
-}
-
static int process_bhi_transition(
struct mhi_device_ctxt *mhi_dev_ctxt,
enum STATE_TRANSITION cur_work_item)
@@ -364,7 +341,6 @@ static int process_ready_transition(
}
write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
- mhi_dev_ctxt->flags.stop_threads = 0;
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, MHICTRL,
MHICTRL_MHISTATE_MASK,
@@ -439,16 +415,6 @@ static int process_reset_transition(
return r;
}
-static int process_syserr_transition(
- struct mhi_device_ctxt *mhi_dev_ctxt,
- enum STATE_TRANSITION cur_work_item)
-{
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Entered with State %s\n",
- TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
- return -EIO;
-}
-
static void enable_clients(struct mhi_device_ctxt *mhi_dev_ctxt,
enum MHI_EXEC_ENV exec_env)
{
@@ -510,9 +476,6 @@ static int process_amss_transition(
mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
return r;
}
- read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock);
- ring_all_chan_dbs(mhi_dev_ctxt, true);
- read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Notifying clients that MHI is enabled\n");
enable_clients(mhi_dev_ctxt, mhi_dev_ctxt->dev_exec_env);
@@ -521,9 +484,6 @@ static int process_amss_transition(
"MHI is initialized\n");
}
- read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock);
- ring_all_ev_dbs(mhi_dev_ctxt);
- read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
complete(&mhi_dev_ctxt->cmd_complete);
/*
@@ -574,23 +534,6 @@ static int process_stt_work_item(
case STATE_TRANSITION_AMSS:
r = process_amss_transition(mhi_dev_ctxt, cur_work_item);
break;
- case STATE_TRANSITION_M0:
- r = process_m0_transition(mhi_dev_ctxt, cur_work_item);
- break;
- case STATE_TRANSITION_M3:
- r = process_m3_transition(mhi_dev_ctxt, cur_work_item);
- break;
- case STATE_TRANSITION_SYS_ERR:
- r = process_syserr_transition(mhi_dev_ctxt,
- cur_work_item);
- break;
- case STATE_TRANSITION_LINK_DOWN:
- r = process_link_down_transition(mhi_dev_ctxt,
- cur_work_item);
- break;
- case STATE_TRANSITION_WAKE:
- r = process_wake_transition(mhi_dev_ctxt, cur_work_item);
- break;
case STATE_TRANSITION_BHIE:
r = process_bhie_transition(mhi_dev_ctxt, cur_work_item);
break;
@@ -603,42 +546,26 @@ static int process_stt_work_item(
return r;
}
-int mhi_state_change_thread(void *ctxt)
+void mhi_state_change_worker(struct work_struct *work)
{
int r = 0;
- unsigned long flags = 0;
- struct mhi_device_ctxt *mhi_dev_ctxt = (struct mhi_device_ctxt *)ctxt;
+ struct mhi_device_ctxt *mhi_dev_ctxt = container_of(work,
+ struct mhi_device_ctxt,
+ st_thread_worker);
enum STATE_TRANSITION cur_work_item;
struct mhi_state_work_queue *work_q =
&mhi_dev_ctxt->state_change_work_item_list;
struct mhi_ring *state_change_q = &work_q->q_info;
- for (;;) {
- r = wait_event_interruptible(
- *mhi_dev_ctxt->mhi_ev_wq.state_change_event,
- ((work_q->q_info.rp != work_q->q_info.wp) &&
- !mhi_dev_ctxt->flags.st_thread_stopped));
- if (r) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Caught signal %d, quitting\n", r);
- return 0;
- }
-
- if (mhi_dev_ctxt->flags.kill_threads) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Caught exit signal, quitting\n");
- return 0;
- }
- mhi_dev_ctxt->flags.st_thread_stopped = 0;
- spin_lock_irqsave(work_q->q_lock, flags);
+ while (work_q->q_info.rp != work_q->q_info.wp) {
+ spin_lock_irq(work_q->q_lock);
cur_work_item = *(enum STATE_TRANSITION *)(state_change_q->rp);
r = ctxt_del_element(&work_q->q_info, NULL);
MHI_ASSERT(r == 0,
"Failed to delete element from STT workqueue\n");
- spin_unlock_irqrestore(work_q->q_lock, flags);
+ spin_unlock_irq(work_q->q_lock);
r = process_stt_work_item(mhi_dev_ctxt, cur_work_item);
}
- return 0;
}
/**
@@ -673,6 +600,6 @@ int mhi_init_state_transition(struct mhi_device_ctxt *mhi_dev_ctxt,
r = ctxt_add_element(stt_ring, (void **)&cur_work_item);
BUG_ON(r);
spin_unlock_irqrestore(work_q->q_lock, flags);
- wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.state_change_event);
+ schedule_work(&mhi_dev_ctxt->st_thread_worker);
return r;
}