Merge "msm: mhi: Send Ch cmd ack in async fashion"

This commit is contained in:
qctecmdr 2021-06-23 03:51:22 -07:00 • committed by Gerrit - the friendly Code Review server
commit 64c433fac3
2 changed files with 198 additions and 29 deletions

View file

@ -87,6 +87,10 @@ static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi,
static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi,
struct event_req *ereq);
static void mhi_dev_event_msi_cb(void *req);
static void mhi_dev_cmd_event_msi_cb(void *req);
static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi);
static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS];
static DECLARE_COMPLETION(read_from_host);
@ -262,7 +266,7 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq)
{
struct ep_pcie_msi_config cfg;
struct mhi_addr msi_addr;
struct mhi_dev_channel *ch = ereq->context;
struct mhi_dev_channel *ch;
uint64_t evnt_ring_idx = mhi->ev_ring_start + ereq->event_ring;
struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx];
union mhi_dev_ring_ctx *ctx;
@ -283,14 +287,23 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq)
msi_addr.phy_addr = ring->msi_buf_dma_handle;
ereq->event_type = SEND_MSI;
ereq->msi_cb = mhi_dev_event_msi_cb;
if (!ereq->is_cmd_cpl) {
ch = ereq->context;
ereq->msi_cb = mhi_dev_event_msi_cb;
ch->msi_cnt++;
mhi_log(MHI_MSG_VERBOSE,
"Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n",
ctx->ev.msivec, msi_addr.host_pa,
*ring->msi_buf, ch->ch_id,
ch->msi_cnt, ereq->flush_num);
} else {
ereq->msi_cb = mhi_dev_cmd_event_msi_cb;
mhi_log(MHI_MSG_VERBOSE,
"Sending MSI %d to 0x%llx as data = 0x%x for cmd ack, ereq flush_num %d\n",
ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf,
ereq->flush_num);
}
ch->msi_cnt++;
mhi_log(MHI_MSG_VERBOSE,
"Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n",
ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf, ch->ch_id,
ch->msi_cnt, ereq->flush_num);
mhi_ctx->write_to_host(mhi, &msi_addr, ereq, MHI_DEV_DMA_ASYNC);
return 0;
@ -314,6 +327,27 @@ static void mhi_dev_event_rd_offset_completion_cb(void *req)
sizeof(uint64_t), DMA_TO_DEVICE);
}
static void mhi_dev_cmd_event_msi_cb(void *req)
{
struct mhi_cmd_cmpl_ctx *cmd_ctx;
struct mhi_dev *mhi;
struct event_req *ereq = req;
unsigned long flags;
mhi_log(MHI_MSG_VERBOSE, "MSI completed for flush req %d\n",
ereq->flush_num);
/*Cmd completion handling*/
mhi = ereq->context;
cmd_ctx = mhi->cmd_ctx;
cmd_ctx->cmd_buf_wp += ereq->num_events;
if (cmd_ctx->cmd_buf_wp == NUM_CMD_EVENTS_DEFAULT)
cmd_ctx->cmd_buf_wp = 0;
spin_lock_irqsave(&mhi->lock, flags);
list_add_tail(&ereq->list, &cmd_ctx->cmd_req_buffers);
spin_unlock_irqrestore(&mhi->lock, flags);
}
static void mhi_dev_event_msi_cb(void *req)
{
struct event_req *ereq = req;
@ -401,7 +435,8 @@ static int mhi_trigger_msi_edma(struct mhi_dev_ring *ring, u32 idx)
}
static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
struct event_req *ereq, uint32_t evt_len)
struct event_req *ereq, uint32_t evt_len,
enum mhi_dev_tr_compl_evt_type event_type)
{
int rc = 0;
uint64_t evnt_ring_idx = mhi->ev_ring_start + evnt_ring;
@ -430,25 +465,25 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
return rc;
}
}
ch = ereq->context;
/* Check the limits of the buffer to be flushed */
if (ereq->tr_events < ch->tr_events ||
(ereq->tr_events + ereq->num_events) >
(ch->tr_events + ch->evt_buf_size)) {
pr_err("%s: Invalid completion event buffer!\n", __func__);
mhi_log(MHI_MSG_ERROR,
"Invalid cmpl evt buf - start %pK, end %pK\n",
ereq->tr_events, ereq->tr_events + ereq->num_events);
return -EINVAL;
}
mutex_lock(&ring->event_lock);
mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n",
ereq->num_events, ch->ch_id);
/* add the events */
ereq->client_cb = mhi_dev_event_buf_completion_cb;
ereq->is_cmd_cpl = (event_type == SEND_CMD_CMP) ? true:false;
ereq->event_type = SEND_EVENT_BUFFER;
if (!ereq->is_cmd_cpl) {
ch = ereq->context;
mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n",
ereq->num_events, ch->ch_id);
} else {
mhi_log(MHI_MSG_VERBOSE,
"Flushing %d cmpl events of cmd ring\n",
ereq->num_events);
}
rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len);
if (rc) {
pr_err("%s(): error in adding element rc %d\n", __func__, rc);
@ -506,6 +541,55 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
return rc;
}
static int mhi_dev_flush_cmd_completion_events(struct mhi_dev *mhi,
union mhi_dev_ring_element_type *el)
{
struct mhi_cmd_cmpl_ctx *cmd_ctx = mhi->cmd_ctx;
unsigned long flags;
struct event_req *flush_ereq;
union mhi_dev_ring_element_type *compl_ev;
int rc = 0;
/*cmd completions are sent on event ring 0 always*/
if (!mhi->cmd_ctx) {
if (mhi_dev_alloc_cmd_ack_buf_req(mhi)) {
mhi_log(MHI_MSG_ERROR, "Alloc cmd ack buff failed");
return -ENOMEM;
}
}
cmd_ctx = mhi->cmd_ctx;
if (list_empty(&cmd_ctx->cmd_req_buffers)) {
mhi_log(MHI_MSG_ERROR, "cmd req buff list is empty");
return -ENOMEM;
}
spin_lock_irqsave(&mhi->lock, flags);
flush_ereq = container_of(cmd_ctx->cmd_req_buffers.next,
struct event_req, list);
list_del_init(&flush_ereq->list);
flush_ereq->context = mhi;
spin_unlock_irqrestore(&mhi->lock, flags);
compl_ev = cmd_ctx->cmd_events + cmd_ctx->cmd_buf_rp;
memcpy(compl_ev, el, sizeof(union mhi_dev_ring_element_type));
cmd_ctx->cmd_buf_rp++;
if (cmd_ctx->cmd_buf_rp == NUM_CMD_EVENTS_DEFAULT)
cmd_ctx->cmd_buf_rp = 0;
flush_ereq->tr_events = compl_ev;
rc = mhi_dev_send_multiple_tr_events(mhi,
0,
flush_ereq,
(1 *
sizeof(union mhi_dev_ring_element_type)),
SEND_CMD_CMP);
if (rc) {
mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n");
return rc;
}
return rc;
}
static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi,
struct mhi_dev_channel *ch)
{
@ -539,11 +623,25 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi,
flush_ereq->flush_num = ch->flush_req_cnt;
mhi_log(MHI_MSG_DBG, "Flush num %d called for ch %d\n",
ch->flush_req_cnt, ch->ch_id);
/* Check the limits of the buffer to be flushed */
if (flush_ereq->tr_events < ch->tr_events ||
(flush_ereq->tr_events + flush_ereq->num_events) >
(ch->tr_events + ch->evt_buf_size)) {
pr_err("%s: Invalid completion event buffer!\n",
__func__);
mhi_log(MHI_MSG_ERROR,
"Invalid cmpl evt buf - start %pK, end %pK\n",
flush_ereq->tr_events,
flush_ereq->tr_events + flush_ereq->num_events);
return -EINVAL;
}
rc = mhi_dev_send_multiple_tr_events(mhi,
mhi->ch_ctx_cache[ch->ch_id].err_indx,
flush_ereq,
(flush_ereq->num_events *
sizeof(union mhi_dev_ring_element_type)));
sizeof(union mhi_dev_ring_element_type)),
SEND_EVENT_BUFFER);
if (rc) {
mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n");
break;
@ -1608,7 +1706,7 @@ int mhi_dev_send_state_change_event(struct mhi_dev *mhi,
event.evt_state_change.type = MHI_DEV_RING_EL_MHI_STATE_CHG;
event.evt_state_change.mhistate = state;
return mhi_dev_send_event(mhi, 0, &event);
return mhi_dev_flush_cmd_completion_events(mhi, &event);
}
EXPORT_SYMBOL(mhi_dev_send_state_change_event);
@ -1619,7 +1717,7 @@ int mhi_dev_send_ee_event(struct mhi_dev *mhi, enum mhi_dev_execenv exec_env)
event.evt_ee_state.type = MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY;
event.evt_ee_state.execenv = exec_env;
return mhi_dev_send_event(mhi, 0, &event);
return mhi_dev_flush_cmd_completion_events(mhi, &event);
}
EXPORT_SYMBOL(mhi_dev_send_ee_event);
@ -1669,7 +1767,7 @@ static int mhi_dev_send_cmd_comp_event(struct mhi_dev *mhi,
(size_t) event.evt_cmd_comp.ptr);
event.evt_cmd_comp.type = MHI_DEV_RING_EL_CMD_COMPLETION_EVT;
event.evt_cmd_comp.code = code;
return mhi_dev_send_event(mhi, 0, &event);
return mhi_dev_flush_cmd_completion_events(mhi, &event);
}
static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id,
@ -1852,7 +1950,7 @@ send_start_completion_event:
event.evt_cmd_comp.code =
MHI_CMD_COMPL_CODE_UNDEFINED;
rc = mhi_dev_send_event(mhi, 0, &event);
rc = mhi_dev_flush_cmd_completion_events(mhi, &event);
if (rc) {
pr_err("stop event send failed\n");
return;
@ -1912,7 +2010,7 @@ send_start_completion_event:
event.evt_cmd_comp.code =
MHI_CMD_COMPL_CODE_UNDEFINED;
rc = mhi_dev_send_event(mhi, 0, &event);
rc = mhi_dev_flush_cmd_completion_events(mhi, &event);
if (rc) {
pr_err("stop event send failed\n");
return;
@ -2723,6 +2821,61 @@ static uint32_t mhi_dev_get_evt_ring_size(struct mhi_dev *mhi, uint32_t ch_id)
mhi->ch_ctx_cache[ch_id].err_indx].ring_size;
}
static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi)
{
int rc = 0;
uint32_t i;
struct mhi_cmd_cmpl_ctx *cmd_ctx;
union mhi_dev_ring_element_type *cmd_events;
mhi->cmd_ctx = kmalloc(sizeof(struct mhi_cmd_cmpl_ctx),
GFP_KERNEL);
if (!mhi->cmd_ctx)
return -ENOMEM;
cmd_ctx = mhi->cmd_ctx;
/* Allocate event requests */
cmd_ctx->ereqs = kcalloc(NUM_CMD_EVENTS_DEFAULT,
sizeof(*cmd_ctx->ereqs),
GFP_KERNEL);
if (!cmd_ctx->ereqs) {
goto free_ereqs;
return -ENOMEM;
}
/* Allocate buffers to queue transfer completion events */
cmd_ctx->cmd_events = kcalloc(NUM_CMD_EVENTS_DEFAULT,
sizeof(*cmd_events),
GFP_KERNEL);
if (!cmd_ctx->cmd_events) {
rc = -ENOMEM;
goto free_ereqs;
}
/* Organize event flush requests into a linked list */
INIT_LIST_HEAD(&cmd_ctx->cmd_req_buffers);
for (i = 0; i < NUM_CMD_EVENTS_DEFAULT; ++i) {
list_add_tail(&cmd_ctx->ereqs[i].list,
&cmd_ctx->cmd_req_buffers);
}
/*
* Initialize cmpl event buffer indexes - cmd_buf_rp and
* cmd_buf_wp point to the first and last free index available.
*/
cmd_ctx->cmd_buf_rp = 0;
cmd_ctx->cmd_buf_wp = NUM_CMD_EVENTS_DEFAULT - 1;
return 0;
free_ereqs:
kfree(mhi->cmd_ctx);
kfree(cmd_ctx->ereqs);
cmd_ctx->ereqs = NULL;
mhi->cmd_ctx = NULL;
return rc;
}
static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi,
struct mhi_dev_channel *ch, struct mhi_dev_ring *evt_ring)
{

View file

@ -271,6 +271,8 @@ struct mhi_config {
/* maximum transfer completion events buffer */
#define NUM_TR_EVENTS_DEFAULT 128
#define NUM_CMD_EVENTS_DEFAULT 20
/* Set flush threshold to 80% of event buf size */
#define MHI_CMPL_EVT_FLUSH_THRSHLD(n) ((n * 8) / 10)
@ -354,7 +356,8 @@ enum mhi_dev_ch_operation {
enum mhi_dev_tr_compl_evt_type {
SEND_EVENT_BUFFER,
SEND_EVENT_RD_OFFSET,
SEND_MSI
SEND_MSI,
SEND_CMD_CMP,
};
enum mhi_dev_transfer_type {
@ -448,6 +451,18 @@ struct event_req {
void (*msi_cb)(void *req);
struct list_head list;
u32 flush_num;
bool is_cmd_cpl;
};
struct mhi_cmd_cmpl_ctx {
/* Indices for completion event buffer */
uint32_t cmd_buf_rp;
uint32_t cmd_buf_wp;
uint32_t cmd_buf_size;
bool mem_allocated;
struct list_head cmd_req_buffers;
struct event_req *ereqs;
union mhi_dev_ring_element_type *cmd_events;
};
struct mhi_dev_channel {
@ -531,6 +546,7 @@ struct mhi_dev {
struct mhi_dev_ring *ring;
int mhi_irq;
struct mhi_dev_channel *ch;
struct mhi_cmd_cmpl_ctx *cmd_ctx;
int ctrl_int;
int cmd_int;