summaryrefslogtreecommitdiff
path: root/drivers/platform/msm
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2017-02-25 19:49:35 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2017-02-25 19:49:34 -0800
commit7a3aebc93ab37cc874019a89949e6255114da780 (patch)
treecf484599ea834330fc7e6df9c283867fd7fa986b /drivers/platform/msm
parenta46c000c6597e4f990b2c704d4ba4b1c2cb6741e (diff)
parentbdfe181b250256f4663e06983ad8fafae7fb3cfc (diff)
Merge "mhi: core: Mark unprocessed events as STALE"
Diffstat (limited to 'drivers/platform/msm')
-rw-r--r--drivers/platform/msm/mhi/mhi.h2
-rw-r--r--drivers/platform/msm/mhi/mhi_event.c3
-rw-r--r--drivers/platform/msm/mhi/mhi_init.c1
-rw-r--r--drivers/platform/msm/mhi/mhi_isr.c37
-rw-r--r--drivers/platform/msm/mhi/mhi_main.c103
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.