diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2017-02-25 19:49:35 -0800 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-02-25 19:49:34 -0800 |
| commit | 7a3aebc93ab37cc874019a89949e6255114da780 (patch) | |
| tree | cf484599ea834330fc7e6df9c283867fd7fa986b /drivers/platform/msm | |
| parent | a46c000c6597e4f990b2c704d4ba4b1c2cb6741e (diff) | |
| parent | bdfe181b250256f4663e06983ad8fafae7fb3cfc (diff) | |
Merge "mhi: core: Mark unprocessed events as STALE"
Diffstat (limited to 'drivers/platform/msm')
| -rw-r--r-- | drivers/platform/msm/mhi/mhi.h | 2 | ||||
| -rw-r--r-- | drivers/platform/msm/mhi/mhi_event.c | 3 | ||||
| -rw-r--r-- | drivers/platform/msm/mhi/mhi_init.c | 1 | ||||
| -rw-r--r-- | drivers/platform/msm/mhi/mhi_isr.c | 37 | ||||
| -rw-r--r-- | drivers/platform/msm/mhi/mhi_main.c | 103 |
5 files changed, 96 insertions, 50 deletions
diff --git a/drivers/platform/msm/mhi/mhi.h b/drivers/platform/msm/mhi/mhi.h index 6165d30c47a0..3d40d114437a 100644 --- a/drivers/platform/msm/mhi/mhi.h +++ b/drivers/platform/msm/mhi/mhi.h @@ -206,6 +206,7 @@ enum MHI_PKT_TYPE { MHI_PKT_TYPE_CMD_COMPLETION_EVENT = 0x21, MHI_PKT_TYPE_TX_EVENT = 0x22, MHI_PKT_TYPE_EE_EVENT = 0x40, + MHI_PKT_TYPE_STALE_EVENT, /* Internal event */ MHI_PKT_TYPE_SYS_ERR_EVENT = 0xFF, }; @@ -310,6 +311,7 @@ struct mhi_ring { uintptr_t el_size; u32 overwrite_en; enum MHI_CHAN_DIR dir; + enum MHI_CHAN_STATE ch_state; struct db_mode db_mode; u32 msi_disable_cntr; u32 msi_enable_cntr; diff --git a/drivers/platform/msm/mhi/mhi_event.c b/drivers/platform/msm/mhi/mhi_event.c index 784306256d36..fe163f3895a5 100644 --- a/drivers/platform/msm/mhi/mhi_event.c +++ b/drivers/platform/msm/mhi/mhi_event.c @@ -122,9 +122,11 @@ void ring_ev_db(struct mhi_device_ctxt *mhi_dev_ctxt, u32 event_ring_index) { struct mhi_ring *event_ctxt = NULL; u64 db_value = 0; + unsigned long flags; event_ctxt = &mhi_dev_ctxt->mhi_local_event_ctxt[event_ring_index]; + spin_lock_irqsave(&event_ctxt->ring_lock, flags); db_value = mhi_v2p_addr(mhi_dev_ctxt, MHI_RING_TYPE_EVENT_RING, event_ring_index, (uintptr_t) event_ctxt->wp); @@ -132,6 +134,7 @@ void ring_ev_db(struct mhi_device_ctxt *mhi_dev_ctxt, u32 event_ring_index) mhi_dev_ctxt->mmio_info.event_db_addr, event_ring_index, db_value); + spin_unlock_irqrestore(&event_ctxt->ring_lock, flags); } static int mhi_event_ring_init(struct mhi_event_ctxt *ev_list, diff --git a/drivers/platform/msm/mhi/mhi_init.c b/drivers/platform/msm/mhi/mhi_init.c index 52afc46be6d0..a496c81239bf 100644 --- a/drivers/platform/msm/mhi/mhi_init.c +++ b/drivers/platform/msm/mhi/mhi_init.c @@ -594,6 +594,7 @@ int mhi_init_chan_ctxt(struct mhi_chan_ctxt *cc_list, ring->el_size = sizeof(struct mhi_tx_pkt); ring->overwrite_en = 0; ring->dir = chan_type; + ring->ch_state = MHI_CHAN_STATE_DISABLED; ring->db_mode.db_mode = 1; ring->db_mode.preserve_db_state = (preserve_db_state) ? 1 : 0; ring->db_mode.brstmode = brstmode; diff --git a/drivers/platform/msm/mhi/mhi_isr.c b/drivers/platform/msm/mhi/mhi_isr.c index 7a4c560d2f42..d7c604419593 100644 --- a/drivers/platform/msm/mhi/mhi_isr.c +++ b/drivers/platform/msm/mhi/mhi_isr.c @@ -25,6 +25,7 @@ static int mhi_process_event_ring( union mhi_event_pkt event_to_process; int ret_val = 0; struct mhi_event_ctxt *ev_ctxt = NULL; + unsigned long flags; struct mhi_ring *local_ev_ctxt = &mhi_dev_ctxt->mhi_local_event_ctxt[ev_index]; @@ -38,6 +39,7 @@ static int mhi_process_event_ring( read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); ev_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[ev_index]; + spin_lock_irqsave(&local_ev_ctxt->ring_lock, flags); device_rp = (union mhi_event_pkt *)mhi_p2v_addr( mhi_dev_ctxt, MHI_RING_TYPE_EVENT_RING, @@ -45,19 +47,19 @@ static int mhi_process_event_ring( ev_ctxt->mhi_event_read_ptr); local_rp = (union mhi_event_pkt *)local_ev_ctxt->rp; - + spin_unlock_irqrestore(&local_ev_ctxt->ring_lock, flags); BUG_ON(validate_ev_el_addr(local_ev_ctxt, (uintptr_t)device_rp)); while ((local_rp != device_rp) && (event_quota > 0) && (device_rp != NULL) && (local_rp != NULL)) { + spin_lock_irqsave(&local_ev_ctxt->ring_lock, flags); event_to_process = *local_rp; - read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); recycle_trb_and_ring(mhi_dev_ctxt, local_ev_ctxt, MHI_RING_TYPE_EVENT_RING, ev_index); - read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); + spin_unlock_irqrestore(&local_ev_ctxt->ring_lock, flags); switch (MHI_TRB_READ_INFO(EV_TRB_TYPE, &event_to_process)) { case MHI_PKT_TYPE_CMD_COMPLETION_EVENT: @@ -93,12 +95,28 @@ static int mhi_process_event_ring( break; } case MHI_PKT_TYPE_TX_EVENT: + { + u32 chan; + struct mhi_ring *ring; + __pm_stay_awake(&mhi_dev_ctxt->w_lock); - parse_xfer_event(mhi_dev_ctxt, - &event_to_process, - ev_index); + chan = MHI_EV_READ_CHID(EV_CHID, &event_to_process); + if (unlikely(!VALID_CHAN_NR(chan))) { + mhi_log(MHI_MSG_ERROR, + "Invalid chan:%d\n", + chan); + break; + } + ring = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; + spin_lock_bh(&ring->ring_lock); + if (ring->ch_state == MHI_CHAN_STATE_ENABLED) + parse_xfer_event(mhi_dev_ctxt, + &event_to_process, + ev_index); + spin_unlock_bh(&ring->ring_lock); __pm_relax(&mhi_dev_ctxt->w_lock); break; + } case MHI_PKT_TYPE_STATE_CHANGE_EVENT: { enum STATE_TRANSITION new_state; @@ -153,6 +171,11 @@ static int mhi_process_event_ring( } break; } + case MHI_PKT_TYPE_STALE_EVENT: + mhi_log(MHI_MSG_INFO, + "Stale Event received for chan:%u\n", + MHI_EV_READ_CHID(EV_CHID, local_rp)); + break; case MHI_PKT_TYPE_SYS_ERR_EVENT: mhi_log(MHI_MSG_INFO, "MHI System Error Detected. Triggering Reset\n"); @@ -165,12 +188,14 @@ static int mhi_process_event_ring( &event_to_process)); break; } + spin_lock_irqsave(&local_ev_ctxt->ring_lock, flags); local_rp = (union mhi_event_pkt *)local_ev_ctxt->rp; device_rp = (union mhi_event_pkt *)mhi_p2v_addr( mhi_dev_ctxt, MHI_RING_TYPE_EVENT_RING, ev_index, ev_ctxt->mhi_event_read_ptr); + spin_unlock_irqrestore(&local_ev_ctxt->ring_lock, flags); ret_val = 0; --event_quota; } diff --git a/drivers/platform/msm/mhi/mhi_main.c b/drivers/platform/msm/mhi/mhi_main.c index a873ea9055fc..430dc918af7e 100644 --- a/drivers/platform/msm/mhi/mhi_main.c +++ b/drivers/platform/msm/mhi/mhi_main.c @@ -277,6 +277,7 @@ int mhi_open_channel(struct mhi_client_handle *client_handle) { int ret_val = 0; struct mhi_device_ctxt *mhi_dev_ctxt; + struct mhi_ring *chan_ring; int chan; struct mhi_chan_cfg *cfg; struct mhi_cmd_complete_event_pkt cmd_event_pkt; @@ -295,6 +296,7 @@ int mhi_open_channel(struct mhi_client_handle *client_handle) chan = client_handle->chan_info.chan_nr; cfg = &mhi_dev_ctxt->mhi_chan_cfg[chan]; + chan_ring = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; mutex_lock(&cfg->chan_lock); mhi_log(MHI_MSG_INFO, "Entered: Client opening chan 0x%x\n", chan); @@ -352,6 +354,9 @@ int mhi_open_channel(struct mhi_client_handle *client_handle) read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); pm_runtime_get(&mhi_dev_ctxt->dev_info->pcie_device->dev); + spin_lock_irq(&chan_ring->ring_lock); + chan_ring->ch_state = MHI_CHAN_STATE_ENABLED; + spin_unlock_irq(&chan_ring->ring_lock); ret_val = mhi_send_cmd(client_handle->mhi_dev_ctxt, MHI_COMMAND_START_CHAN, chan); @@ -462,6 +467,7 @@ void mhi_close_channel(struct mhi_client_handle *client_handle) struct mhi_device_ctxt *mhi_dev_ctxt; struct mhi_cmd_complete_event_pkt cmd_event_pkt; union mhi_cmd_pkt cmd_pkt; + struct mhi_ring *chan_ring; enum MHI_EVENT_CCS ev_code; if (!client_handle || @@ -474,7 +480,13 @@ void mhi_close_channel(struct mhi_client_handle *client_handle) cfg = &mhi_dev_ctxt->mhi_chan_cfg[chan]; mhi_log(MHI_MSG_INFO, "Client attempting to close chan 0x%x\n", chan); + chan_ring = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; mutex_lock(&cfg->chan_lock); + + /* No more processing events for this channel */ + spin_lock_irq(&chan_ring->ring_lock); + chan_ring->ch_state = MHI_CHAN_STATE_DISABLED; + spin_unlock_irq(&chan_ring->ring_lock); init_completion(&cfg->cmd_complete); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); WARN_ON(mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE); @@ -829,8 +841,6 @@ int mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, enum MHI_COMMAND cmd, u32 chan) { union mhi_cmd_pkt *cmd_pkt = NULL; - enum MHI_CHAN_STATE from_state = MHI_CHAN_STATE_DISABLED; - enum MHI_CHAN_STATE to_state = MHI_CHAN_STATE_DISABLED; enum MHI_PKT_TYPE ring_el_type = MHI_PKT_TYPE_NOOP_CMD; int ret_val = 0; unsigned long flags, flags2; @@ -849,33 +859,17 @@ int mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), mhi_dev_ctxt->dev_exec_env, chan, cmd); - from_state = - mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan].chstate; - switch (cmd) { break; case MHI_COMMAND_RESET_CHAN: - to_state = MHI_CHAN_STATE_DISABLED; ring_el_type = MHI_PKT_TYPE_RESET_CHAN_CMD; break; case MHI_COMMAND_START_CHAN: - switch (from_state) { - case MHI_CHAN_STATE_DISABLED: - case MHI_CHAN_STATE_ENABLED: - case MHI_CHAN_STATE_STOP: - to_state = MHI_CHAN_STATE_RUNNING; - break; - default: - mhi_log(MHI_MSG_ERROR, - "Invalid stt cmd 0x%x, from_state 0x%x\n", - cmd, from_state); - ret_val = -EPERM; - goto error_invalid; - } ring_el_type = MHI_PKT_TYPE_START_CHAN_CMD; break; default: mhi_log(MHI_MSG_ERROR, "Bad command received\n"); + return -EINVAL; } spin_lock_irqsave(&mhi_ring->ring_lock, flags); @@ -897,7 +891,7 @@ int mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, "Sent command 0x%x for chan %d\n", cmd, chan); -error_invalid: + mhi_log(MHI_MSG_INFO, "Exited ret %d.\n", ret_val); return ret_val; } @@ -1120,13 +1114,11 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, u32 nr_trb_to_parse; u32 i = 0; u32 ev_code; + struct mhi_ring *local_chan_ctxt; trace_mhi_ev(event); chan = MHI_EV_READ_CHID(EV_CHID, event); - if (unlikely(!VALID_CHAN_NR(chan))) { - mhi_log(MHI_MSG_ERROR, "Bad ring id.\n"); - return -EINVAL; - } + local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; ev_code = MHI_EV_READ_CODE(EV_TRB_CODE, event); client_handle = mhi_dev_ctxt->client_handle_list[chan]; client_handle->pkt_count++; @@ -1147,10 +1139,7 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, dma_addr_t trb_data_loc; u32 ieot_flag; int ret_val; - struct mhi_ring *local_chan_ctxt; - local_chan_ctxt = - &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; phy_ev_trb_loc = MHI_EV_READ_PTR(EV_PTR, event); chan_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan]; @@ -1217,29 +1206,22 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt, case MHI_EVENT_CC_OOB: case MHI_EVENT_CC_DB_MODE: { - struct mhi_ring *chan_ctxt = NULL; u64 db_value = 0; - unsigned long flags; - - chan = MHI_EV_READ_CHID(EV_CHID, event); - chan_ctxt = - &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; mhi_log(MHI_MSG_INFO, "DB_MODE/OOB Detected chan %d.\n", chan); - spin_lock_irqsave(&chan_ctxt->ring_lock, flags); - chan_ctxt->db_mode.db_mode = 1; - if (chan_ctxt->wp != chan_ctxt->rp) { + + local_chan_ctxt->db_mode.db_mode = 1; + if (local_chan_ctxt->wp != local_chan_ctxt->rp) { db_value = mhi_v2p_addr(mhi_dev_ctxt, - MHI_RING_TYPE_XFER_RING, chan, - (uintptr_t) chan_ctxt->wp); - chan_ctxt->db_mode.process_db(mhi_dev_ctxt, + MHI_RING_TYPE_XFER_RING, chan, + (uintptr_t) local_chan_ctxt->wp); + local_chan_ctxt->db_mode.process_db(mhi_dev_ctxt, mhi_dev_ctxt->mmio_info.chan_db_addr, chan, db_value); } client_handle = mhi_dev_ctxt->client_handle_list[chan]; if (client_handle) result->transaction_status = -ENOTCONN; - spin_unlock_irqrestore(&chan_ctxt->ring_lock, flags); break; } case MHI_EVENT_CC_BAD_TRE: @@ -1272,7 +1254,6 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt, u64 db_value = 0; void *removed_element = NULL; void *added_element = NULL; - spinlock_t *lock; unsigned long flags; struct mhi_ring *mhi_ring = &mhi_dev_ctxt-> mhi_local_event_ctxt[ring_index]; @@ -1292,8 +1273,7 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt, if (!MHI_DB_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) return -EACCES; - lock = &mhi_ring->ring_lock; - spin_lock_irqsave(lock, flags); + read_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); db_value = mhi_v2p_addr(mhi_dev_ctxt, ring_type, ring_index, @@ -1301,7 +1281,7 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_ring->db_mode.process_db(mhi_dev_ctxt, mhi_dev_ctxt->mmio_info.event_db_addr, ring_index, db_value); - spin_unlock_irqrestore(lock, flags); + read_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); return 0; @@ -1313,10 +1293,15 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, u32 chan = 0; int ret_val = 0; struct mhi_ring *local_chan_ctxt; + struct mhi_ring *ev_ring; struct mhi_chan_ctxt *chan_ctxt; + struct mhi_event_ctxt *ev_ctxt = NULL; struct mhi_client_handle *client_handle = NULL; int pending_el = 0, i; struct mhi_ring *bb_ctxt; + unsigned long flags; + union mhi_event_pkt *local_rp = NULL; + union mhi_event_pkt *device_rp = NULL; MHI_TRB_GET_INFO(CMD_TRB_CHID, cmd_pkt, chan); @@ -1330,8 +1315,38 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, client_handle = mhi_dev_ctxt->client_handle_list[chan]; local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; chan_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan]; + ev_ring = &mhi_dev_ctxt-> + mhi_local_event_ctxt[chan_ctxt->mhi_event_ring_index]; + ev_ctxt = &mhi_dev_ctxt-> + dev_space.ring_ctxt.ec_list[chan_ctxt->mhi_event_ring_index]; mhi_log(MHI_MSG_INFO, "Processed cmd reset event\n"); + /* Clear all stale events related to Channel */ + spin_lock_irqsave(&ev_ring->ring_lock, flags); + device_rp = (union mhi_event_pkt *)mhi_p2v_addr( + mhi_dev_ctxt, + MHI_RING_TYPE_EVENT_RING, + chan_ctxt->mhi_event_ring_index, + ev_ctxt->mhi_event_read_ptr); + local_rp = (union mhi_event_pkt *)ev_ring->rp; + while (device_rp != local_rp) { + if (MHI_TRB_READ_INFO(EV_TRB_TYPE, local_rp) == + MHI_PKT_TYPE_TX_EVENT) { + u32 ev_chan = MHI_EV_READ_CHID(EV_CHID, local_rp); + + /* Mark as stale event */ + if (ev_chan == chan) + MHI_TRB_SET_INFO(EV_TRB_TYPE, + local_rp, + MHI_PKT_TYPE_STALE_EVENT); + } + + local_rp++; + if (local_rp == (ev_ring->base + ev_ring->len)) + local_rp = ev_ring->base; + } + spin_unlock_irqrestore(&ev_ring->ring_lock, flags); + /* * If outbound elements are pending, they must be cleared since * they will never be acked after a channel reset. |
