mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-14 00:24:41 -04:00
Merge "msm: mhi_dev: Fix memory leak during channel reset/stop"
This commit is contained in:
commit
3ba33ef735
3 changed files with 246 additions and 85 deletions
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.*/
|
||||
/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.*/
|
||||
|
||||
/*
|
||||
* MSM MHI device core driver.
|
||||
|
|
@ -84,6 +84,10 @@ static int mhi_dev_pcie_notify_event;
|
|||
static void mhi_dev_transfer_completion_cb(void *mreq);
|
||||
static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi,
|
||||
struct mhi_dev_channel *ch, struct mhi_dev_ring *evt_ring);
|
||||
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 struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS];
|
||||
static DECLARE_COMPLETION(read_from_host);
|
||||
static DECLARE_COMPLETION(write_to_host);
|
||||
|
|
@ -165,6 +169,7 @@ void mhi_dev_write_to_host_ipa(struct mhi_dev *mhi, struct mhi_addr *transfer,
|
|||
int rc = 0;
|
||||
uint64_t bit_40 = ((u64) 1) << 40, host_addr_pa = 0, offset = 0;
|
||||
dma_addr_t dma;
|
||||
void (*cb_func)(void *req);
|
||||
|
||||
if (WARN_ON(!mhi))
|
||||
return;
|
||||
|
|
@ -183,11 +188,12 @@ void mhi_dev_write_to_host_ipa(struct mhi_dev *mhi, struct mhi_addr *transfer,
|
|||
(int) transfer->size);
|
||||
if (tr_type == MHI_DEV_DMA_ASYNC) {
|
||||
/*
|
||||
* Event read pointer memory is dma_alloc_coherent memory
|
||||
* don't need to dma_map. Assigns the physical address in
|
||||
* phy_addr.
|
||||
* Event read pointer memory and MSI buf are dma_alloc_coherent
|
||||
* memory so don't need to dma_map. Use the physical address
|
||||
* passed in phy_addr.
|
||||
*/
|
||||
if (transfer->phy_addr)
|
||||
if (ereq->event_type == SEND_EVENT_RD_OFFSET ||
|
||||
ereq->event_type == SEND_MSI)
|
||||
dma = transfer->phy_addr;
|
||||
else
|
||||
dma = dma_map_single(&mhi->pdev->dev,
|
||||
|
|
@ -196,6 +202,7 @@ void mhi_dev_write_to_host_ipa(struct mhi_dev *mhi, struct mhi_addr *transfer,
|
|||
if (ereq->event_type == SEND_EVENT_BUFFER) {
|
||||
ereq->dma = dma;
|
||||
ereq->dma_len = transfer->size;
|
||||
cb_func = ereq->client_cb;
|
||||
} else if (ereq->event_type == SEND_EVENT_RD_OFFSET) {
|
||||
/*
|
||||
* Event read pointer memory is dma_alloc_coherent
|
||||
|
|
@ -205,10 +212,13 @@ void mhi_dev_write_to_host_ipa(struct mhi_dev *mhi, struct mhi_addr *transfer,
|
|||
ereq->event_rd_dma = 0;
|
||||
else
|
||||
ereq->event_rd_dma = dma;
|
||||
cb_func = ereq->rd_offset_cb;
|
||||
} else {
|
||||
cb_func = ereq->msi_cb;
|
||||
}
|
||||
rc = ipa_dma_async_memcpy(host_addr_pa, (uint64_t) dma,
|
||||
rc = ipa_dma_async_memcpy(host_addr_pa, (uint64_t)dma,
|
||||
(int)transfer->size,
|
||||
ereq->client_cb, ereq);
|
||||
cb_func, ereq);
|
||||
if (rc)
|
||||
pr_err("error while writing to host:%d\n", rc);
|
||||
} else if (tr_type == MHI_DEV_DMA_SYNC) {
|
||||
|
|
@ -235,11 +245,55 @@ static void mhi_dev_event_buf_completion_cb(void *req)
|
|||
{
|
||||
struct event_req *ereq = req;
|
||||
|
||||
if (ereq)
|
||||
if (!ereq) {
|
||||
mhi_log(MHI_MSG_ERROR, "Null ereq\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ereq->dma && ereq->dma_len)
|
||||
dma_unmap_single(&mhi_ctx->pdev->dev, ereq->dma,
|
||||
ereq->dma_len, DMA_TO_DEVICE);
|
||||
else
|
||||
mhi_log(MHI_MSG_ERROR, "event req is null\n");
|
||||
ereq->dma_len, DMA_TO_DEVICE);
|
||||
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Event buf dma completed for flush req %d\n", ereq->flush_num);
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
int rc;
|
||||
|
||||
rc = ep_pcie_get_msi_config(mhi->phandle, &cfg);
|
||||
if (rc) {
|
||||
pr_err("Error retrieving pcie msi logic\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
ctx = (union mhi_dev_ring_ctx *)&mhi->ev_ctx_cache[ereq->event_ring];
|
||||
|
||||
msi_addr.size = sizeof(uint32_t);
|
||||
msi_addr.host_pa = (uint64_t)((uint64_t)cfg.upper << 32) |
|
||||
(uint64_t)cfg.lower;
|
||||
*ring->msi_buf = cfg.data + ctx->ev.msivec;
|
||||
msi_addr.phy_addr = ring->msi_buf_dma_handle;
|
||||
|
||||
ereq->event_type = SEND_MSI;
|
||||
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);
|
||||
mhi_ctx->write_to_host(mhi, &msi_addr, ereq, MHI_DEV_DMA_ASYNC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -250,25 +304,35 @@ static void mhi_dev_event_buf_completion_cb(void *req)
|
|||
*/
|
||||
static void mhi_dev_event_rd_offset_completion_cb(void *req)
|
||||
{
|
||||
union mhi_dev_ring_ctx *ctx;
|
||||
int rc;
|
||||
struct event_req *ereq = req;
|
||||
struct mhi_dev_channel *ch = ereq->context;
|
||||
struct mhi_dev *mhi = ch->ring->mhi_dev;
|
||||
unsigned long flags;
|
||||
|
||||
mhi_log(MHI_MSG_VERBOSE, "Rd offset dma completed for flush req %d\n",
|
||||
ereq->flush_num);
|
||||
|
||||
if (ereq->event_rd_dma)
|
||||
dma_unmap_single(&mhi_ctx->pdev->dev, ereq->event_rd_dma,
|
||||
sizeof(uint64_t), DMA_TO_DEVICE);
|
||||
/* rp update in host memory should be flushed before sending an MSI */
|
||||
wmb();
|
||||
ctx = (union mhi_dev_ring_ctx *)&mhi->ev_ctx_cache[ereq->event_ring];
|
||||
if (mhi_ctx->use_ipa) {
|
||||
rc = ep_pcie_trigger_msi(mhi_ctx->phandle, ctx->ev.msivec);
|
||||
if (rc)
|
||||
pr_err("%s: error sending in msi\n", __func__);
|
||||
sizeof(uint64_t), DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
static void mhi_dev_event_msi_cb(void *req)
|
||||
{
|
||||
struct event_req *ereq = req;
|
||||
struct mhi_dev_channel *ch;
|
||||
struct mhi_dev *mhi;
|
||||
unsigned long flags;
|
||||
|
||||
if (!ereq) {
|
||||
mhi_log(MHI_MSG_WARNING,
|
||||
"Null ereq, valid only for sync dma and cmd ack to host\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ch = ereq->context;
|
||||
mhi = ch->ring->mhi_dev;
|
||||
|
||||
mhi_log(MHI_MSG_VERBOSE, "MSI completed for flush req %d\n",
|
||||
ereq->flush_num);
|
||||
|
||||
/* Add back the flushed events space to the event buffer */
|
||||
ch->evt_buf_wp = ereq->start + ereq->num_events;
|
||||
if (ch->evt_buf_wp == ch->evt_buf_size)
|
||||
|
|
@ -292,7 +356,7 @@ static int mhi_trigger_msi_edma(struct mhi_dev_ring *ring, u32 idx)
|
|||
{
|
||||
struct dma_async_tx_descriptor *descriptor;
|
||||
struct ep_pcie_msi_config cfg;
|
||||
struct msi_buf_cb_data *msi_buf;
|
||||
struct msi_buf_cb_data *msi_buffer;
|
||||
int rc;
|
||||
unsigned long flags;
|
||||
|
||||
|
|
@ -313,12 +377,12 @@ static int mhi_trigger_msi_edma(struct mhi_dev_ring *ring, u32 idx)
|
|||
|
||||
spin_lock_irqsave(&mhi_ctx->msi_lock, flags);
|
||||
|
||||
msi_buf = &ring->msi_buf;
|
||||
msi_buf->buf[0] = (mhi_ctx->msi_data + idx);
|
||||
msi_buffer = &ring->msi_buffer;
|
||||
msi_buffer->buf[0] = (mhi_ctx->msi_data + idx);
|
||||
|
||||
descriptor = dmaengine_prep_dma_memcpy(mhi_ctx->tx_dma_chan,
|
||||
(dma_addr_t)(mhi_ctx->msi_lower),
|
||||
msi_buf->dma_addr,
|
||||
msi_buffer->dma_addr,
|
||||
sizeof(u32),
|
||||
DMA_PREP_INTERRUPT);
|
||||
if (!descriptor) {
|
||||
|
|
@ -327,7 +391,7 @@ static int mhi_trigger_msi_edma(struct mhi_dev_ring *ring, u32 idx)
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
descriptor->callback_param = msi_buf;
|
||||
descriptor->callback_param = msi_buffer;
|
||||
descriptor->callback = msi_trigger_completion_cb;
|
||||
dma_async_issue_pending(mhi_ctx->tx_dma_chan);
|
||||
|
||||
|
|
@ -384,16 +448,22 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
|
|||
/* add the events */
|
||||
ereq->client_cb = mhi_dev_event_buf_completion_cb;
|
||||
ereq->event_type = SEND_EVENT_BUFFER;
|
||||
|
||||
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);
|
||||
mutex_unlock(&ring->event_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
ring->ring_ctx_shadow->ev.rp = (ring->rd_offset *
|
||||
sizeof(union mhi_dev_ring_element_type)) +
|
||||
ring->ring_ctx->generic.rbase;
|
||||
|
||||
ring->evt_rp_cache[ring->rd_offset] = ring->ring_ctx_shadow->ev.rp;
|
||||
mhi_log(MHI_MSG_VERBOSE, "Caching rp %llx for rd offset %d\n",
|
||||
ring->evt_rp_cache[ring->rd_offset], ring->rd_offset);
|
||||
|
||||
mhi_log(MHI_MSG_VERBOSE, "ev.rp = %llx for %lld\n",
|
||||
ring->ring_ctx_shadow->ev.rp, evnt_ring_idx);
|
||||
|
||||
|
|
@ -402,35 +472,37 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
|
|||
sizeof(struct mhi_dev_ev_ctx) *
|
||||
evnt_ring) + (size_t)&ring->ring_ctx->ev.rp -
|
||||
(size_t)ring->ring_ctx;
|
||||
/*
|
||||
* As ev_ctx_cache memory is dma_alloc_coherent, dma_map_single
|
||||
* should not be called. Pass physical address to write to host.
|
||||
*/
|
||||
transfer_addr.phy_addr = (mhi->ev_ctx_cache_dma_handle +
|
||||
sizeof(struct mhi_dev_ev_ctx) * evnt_ring) +
|
||||
(size_t)&ring->ring_ctx->ev.rp -
|
||||
(size_t)ring->ring_ctx;
|
||||
transfer_addr.phy_addr = ring->evt_rp_cache_dma_handle +
|
||||
(sizeof(uint64_t) * ring->rd_offset);
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"RP phy addr = 0x%x for ring rd offset %d\n",
|
||||
transfer_addr.phy_addr, ring->rd_offset);
|
||||
} else {
|
||||
transfer_addr.device_va = (mhi->ev_ctx_shadow.device_va +
|
||||
sizeof(struct mhi_dev_ev_ctx) *
|
||||
evnt_ring) + (size_t)&ring->ring_ctx->ev.rp -
|
||||
(size_t)ring->ring_ctx;
|
||||
transfer_addr.device_va =
|
||||
(size_t)(ring->evt_rp_cache + ring->rd_offset);
|
||||
}
|
||||
|
||||
transfer_addr.virt_addr = &ring->ring_ctx_shadow->ev.rp;
|
||||
transfer_addr.virt_addr = &ring->evt_rp_cache[ring->rd_offset];
|
||||
transfer_addr.size = sizeof(uint64_t);
|
||||
ereq->event_type = SEND_EVENT_RD_OFFSET;
|
||||
ereq->client_cb = mhi_dev_event_rd_offset_completion_cb;
|
||||
ereq->rd_offset_cb = mhi_dev_event_rd_offset_completion_cb;
|
||||
ereq->event_ring = evnt_ring;
|
||||
|
||||
/* Schedule DMA for event ring RP*/
|
||||
mhi_ctx->write_to_host(mhi, &transfer_addr, ereq, MHI_DEV_DMA_ASYNC);
|
||||
mutex_unlock(&ring->event_lock);
|
||||
|
||||
if (mhi_ctx->use_edma) {
|
||||
rc = mhi_trigger_msi_edma(ring, ctx->ev.msivec);
|
||||
if (rc)
|
||||
pr_err("%s: error sending in msi\n", __func__);
|
||||
} else {
|
||||
/* Schedule DMA for MSI*/
|
||||
rc = mhi_dev_schedule_msi_ipa(mhi, ereq);
|
||||
if (rc)
|
||||
pr_err("%s: error sending in msi\n", __func__);
|
||||
}
|
||||
|
||||
mutex_unlock(&ring->event_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -463,7 +535,10 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi,
|
|||
list_del_init(&flush_ereq->list);
|
||||
spin_unlock_irqrestore(&mhi->lock, flags);
|
||||
|
||||
mhi_log(MHI_MSG_DBG, "Flush called for ch %d\n", ch->ch_id);
|
||||
ch->flush_req_cnt++;
|
||||
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);
|
||||
rc = mhi_dev_send_multiple_tr_events(mhi,
|
||||
mhi->ch_ctx_cache[ch->ch_id].err_indx,
|
||||
flush_ereq,
|
||||
|
|
@ -526,9 +601,24 @@ static int mhi_dev_queue_transfer_completion(struct mhi_req *mreq, bool *flush)
|
|||
compl_ev->evt_tr_comp.ptr = ch->ring->ring_ctx->generic.rbase +
|
||||
mreq->rd_offset * TR_RING_ELEMENT_SZ;
|
||||
ch->evt_buf_rp++;
|
||||
/* Ensure new event is flushed to memory */
|
||||
wmb();
|
||||
if (ch->evt_buf_rp == ch->evt_buf_size)
|
||||
ch->evt_buf_rp = 0;
|
||||
ch->curr_ereq->num_events++;
|
||||
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt ptr : 0x%llx\n",
|
||||
compl_ev->evt_tr_comp.ptr);
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt len : 0x%x\n",
|
||||
compl_ev->evt_tr_comp.len);
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt code :0x%x\n",
|
||||
compl_ev->evt_tr_comp.code);
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt type :0x%x\n",
|
||||
compl_ev->evt_tr_comp.type);
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt chid :0x%x\n",
|
||||
compl_ev->evt_tr_comp.chid);
|
||||
mhi_log(MHI_MSG_VERBOSE, "evt_buf_rp: 0x%x, curr_ereq:0x%x\n",
|
||||
ch->evt_buf_rp, ch->curr_ereq->num_events);
|
||||
/*
|
||||
* It is not necessary to flush when we need to wrap-around, if
|
||||
* we do have free space in the buffer upon wrap-around.
|
||||
|
|
@ -2879,6 +2969,14 @@ int mhi_dev_read_channel(struct mhi_req *mreq)
|
|||
mhi_log(MHI_MSG_ERROR, "invalid mhi request\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (atomic_read(&mhi_ctx->is_suspended)) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"mhi still in suspend, return %d for read ch:%d\n",
|
||||
rc, mreq->client->channel->ch_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
handle_client = mreq->client;
|
||||
ch = handle_client->channel;
|
||||
usr_buf_remaining = mreq->len;
|
||||
|
|
@ -3590,26 +3688,6 @@ err:
|
|||
|
||||
static int mhi_deinit(struct mhi_dev *mhi)
|
||||
{
|
||||
int i = 0, ring_id = 0;
|
||||
struct mhi_dev_ring *ring;
|
||||
|
||||
ring_id = mhi->cfg.channels + mhi->cfg.event_rings + 1;
|
||||
|
||||
for (i = 0; i < ring_id; i++) {
|
||||
ring = &mhi->ring[i];
|
||||
if (ring->state == RING_STATE_UINT)
|
||||
continue;
|
||||
|
||||
dma_free_coherent(mhi->dev, ring->ring_size *
|
||||
sizeof(union mhi_dev_ring_element_type),
|
||||
ring->ring_cache,
|
||||
ring->ring_cache_dma_handle);
|
||||
|
||||
if (mhi->use_edma)
|
||||
dma_free_coherent(mhi->dev, sizeof(u32),
|
||||
ring->msi_buf.buf,
|
||||
ring->msi_buf.dma_addr);
|
||||
}
|
||||
|
||||
mhi_dev_sm_exit(mhi);
|
||||
|
||||
|
|
@ -3629,10 +3707,11 @@ static int mhi_init(struct mhi_dev *mhi)
|
|||
return rc;
|
||||
}
|
||||
|
||||
mhi->ring = devm_kzalloc(&pdev->dev,
|
||||
(sizeof(struct mhi_dev_ring) *
|
||||
(mhi->cfg.channels + mhi->cfg.event_rings + 1)),
|
||||
GFP_KERNEL);
|
||||
if (!mhi->ring)
|
||||
mhi->ring = devm_kzalloc(&pdev->dev,
|
||||
(sizeof(struct mhi_dev_ring) *
|
||||
(mhi->cfg.channels + mhi->cfg.event_rings + 1)),
|
||||
GFP_KERNEL);
|
||||
if (!mhi->ring)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -3655,8 +3734,10 @@ static int mhi_init(struct mhi_dev *mhi)
|
|||
|
||||
spin_lock_init(&mhi->lock);
|
||||
spin_lock_init(&mhi->msi_lock);
|
||||
mhi->mmio_backup = devm_kzalloc(&pdev->dev,
|
||||
MHI_DEV_MMIO_RANGE, GFP_KERNEL);
|
||||
|
||||
if (!mhi->mmio_backup)
|
||||
mhi->mmio_backup = devm_kzalloc(&pdev->dev, MHI_DEV_MMIO_RANGE, GFP_KERNEL);
|
||||
|
||||
if (!mhi->mmio_backup)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.*/
|
||||
/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.*/
|
||||
|
||||
#ifndef __MHI_H
|
||||
#define __MHI_H
|
||||
|
|
@ -354,6 +354,7 @@ enum mhi_dev_ch_operation {
|
|||
enum mhi_dev_tr_compl_evt_type {
|
||||
SEND_EVENT_BUFFER,
|
||||
SEND_EVENT_RD_OFFSET,
|
||||
SEND_MSI
|
||||
};
|
||||
|
||||
enum mhi_dev_transfer_type {
|
||||
|
|
@ -388,13 +389,21 @@ struct mhi_dev_ring {
|
|||
union mhi_dev_ring_element_type *ring_cache;
|
||||
/* Physical address of the cached ring copy on the device side */
|
||||
dma_addr_t ring_cache_dma_handle;
|
||||
/* Device VA of read pointer array (used only for event rings) */
|
||||
uint64_t *evt_rp_cache;
|
||||
/* PA of the read pointer array (used only for event rings) */
|
||||
dma_addr_t evt_rp_cache_dma_handle;
|
||||
/* Device VA of msi buffer (used only for event rings) */
|
||||
uint32_t *msi_buf;
|
||||
/* PA of msi buf (used only for event rings) */
|
||||
dma_addr_t msi_buf_dma_handle;
|
||||
/* Physical address of the host where we will write/read to/from */
|
||||
struct mhi_addr ring_shadow;
|
||||
/* Ring type - cmd, event, transfer ring and its rp/wp... */
|
||||
union mhi_dev_ring_ctx *ring_ctx;
|
||||
/* ring_ctx_shadow -> tracking ring_ctx in the host */
|
||||
union mhi_dev_ring_ctx *ring_ctx_shadow;
|
||||
struct msi_buf_cb_data msi_buf;
|
||||
struct msi_buf_cb_data msi_buffer;
|
||||
void (*ring_cb)(struct mhi_dev *dev,
|
||||
union mhi_dev_ring_element_type *el,
|
||||
void *ctx);
|
||||
|
|
@ -434,7 +443,10 @@ struct event_req {
|
|||
enum mhi_dev_tr_compl_evt_type event_type;
|
||||
u32 event_ring;
|
||||
void (*client_cb)(void *req);
|
||||
void (*rd_offset_cb)(void *req);
|
||||
void (*msi_cb)(void *req);
|
||||
struct list_head list;
|
||||
u32 flush_num;
|
||||
};
|
||||
|
||||
struct mhi_dev_channel {
|
||||
|
|
@ -478,6 +490,8 @@ struct mhi_dev_channel {
|
|||
/* td size being read/written from/to so far */
|
||||
uint32_t td_size;
|
||||
uint32_t pend_wr_count;
|
||||
uint32_t msi_cnt;
|
||||
uint32_t flush_req_cnt;
|
||||
bool skip_td;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.*/
|
||||
/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
|
|
@ -279,6 +279,7 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring,
|
|||
uint32_t num_elem = 1;
|
||||
uint32_t num_free_elem;
|
||||
struct mhi_dev *mhi_ctx;
|
||||
uint32_t i;
|
||||
|
||||
if (WARN_ON(!ring || !element))
|
||||
return -EINVAL;
|
||||
|
|
@ -310,6 +311,10 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring,
|
|||
} else
|
||||
mhi_dev_ring_inc_index(ring, ring->rd_offset);
|
||||
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Writing %d elements, ring old 0x%x, new 0x%x\n",
|
||||
num_elem, old_offset, ring->rd_offset);
|
||||
|
||||
ring->ring_ctx->generic.rp = (ring->rd_offset *
|
||||
sizeof(union mhi_dev_ring_element_type)) +
|
||||
ring->ring_ctx->generic.rbase;
|
||||
|
|
@ -340,6 +345,19 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Log elements added to ring
|
||||
for (i = 0; i < num_elem; ++i) {
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt ptr : 0x%llx\n",
|
||||
(element + i)->evt_tr_comp.ptr);
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt len : 0x%x\n",
|
||||
(element + i)->evt_tr_comp.len);
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt code :0x%x\n",
|
||||
(element + i)->evt_tr_comp.code);
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt type :0x%x\n",
|
||||
(element + i)->evt_tr_comp.type);
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt chid :0x%x\n",
|
||||
(element + i)->evt_tr_comp.chid);
|
||||
}
|
||||
/* Adding multiple ring elements */
|
||||
if (ring->rd_offset == 0 || (ring->rd_offset > old_offset)) {
|
||||
/* No wrap-around case */
|
||||
|
|
@ -349,6 +367,7 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring,
|
|||
mhi_ctx->write_to_host(ring->mhi_dev, &host_addr,
|
||||
ereq, MHI_DEV_DMA_ASYNC);
|
||||
} else {
|
||||
mhi_log(MHI_MSG_VERBOSE, "Wrap around case\n");
|
||||
/* Wrap-around case - first chunk uses dma sync */
|
||||
host_addr.virt_addr = element;
|
||||
host_addr.size = (ring->ring_size - old_offset) *
|
||||
|
|
@ -385,17 +404,17 @@ EXPORT_SYMBOL(mhi_dev_add_element);
|
|||
|
||||
static int mhi_dev_ring_alloc_msi_buf(struct mhi_dev_ring *ring)
|
||||
{
|
||||
if (ring->msi_buf.buf) {
|
||||
if (ring->msi_buffer.buf) {
|
||||
mhi_log(MHI_MSG_INFO, "MSI buf already allocated\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ring->msi_buf.buf = dma_alloc_coherent(&ring->mhi_dev->pdev->dev,
|
||||
ring->msi_buffer.buf = dma_alloc_coherent(&ring->mhi_dev->pdev->dev,
|
||||
sizeof(u32),
|
||||
&ring->msi_buf.dma_addr,
|
||||
&ring->msi_buffer.dma_addr,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!ring->msi_buf.buf)
|
||||
if (!ring->msi_buffer.buf)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
|
|
@ -424,13 +443,45 @@ int mhi_ring_start(struct mhi_dev_ring *ring, union mhi_dev_ring_ctx *ctx,
|
|||
wr_offset = mhi_dev_ring_addr2ofst(ring,
|
||||
ring->ring_ctx->generic.wp);
|
||||
|
||||
ring->ring_cache = dma_alloc_coherent(mhi->dev,
|
||||
ring->ring_size *
|
||||
sizeof(union mhi_dev_ring_element_type),
|
||||
&ring->ring_cache_dma_handle,
|
||||
GFP_KERNEL);
|
||||
if (!ring->ring_cache)
|
||||
return -ENOMEM;
|
||||
if (!ring->ring_cache) {
|
||||
ring->ring_cache = dma_alloc_coherent(mhi->dev,
|
||||
ring->ring_size *
|
||||
sizeof(union mhi_dev_ring_element_type),
|
||||
&ring->ring_cache_dma_handle,
|
||||
GFP_KERNEL);
|
||||
if (!ring->ring_cache) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"Failed to allocate ring cache\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (ring->type == RING_TYPE_ER) {
|
||||
if (!ring->evt_rp_cache) {
|
||||
ring->evt_rp_cache = dma_alloc_coherent(mhi->dev,
|
||||
sizeof(uint64_t) * ring->ring_size,
|
||||
&ring->evt_rp_cache_dma_handle,
|
||||
GFP_KERNEL);
|
||||
if (!ring->evt_rp_cache) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"Failed to allocate evt rp cache\n");
|
||||
rc = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
if (!ring->msi_buf) {
|
||||
ring->msi_buf = dma_alloc_coherent(mhi->dev,
|
||||
sizeof(uint32_t),
|
||||
&ring->msi_buf_dma_handle,
|
||||
GFP_KERNEL);
|
||||
if (!ring->msi_buf) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"Failed to allocate msi buf\n");
|
||||
rc = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset = (size_t)(ring->ring_ctx->generic.rbase -
|
||||
mhi->ctrl_base.host_pa);
|
||||
|
|
@ -471,7 +522,22 @@ int mhi_ring_start(struct mhi_dev_ring *ring, union mhi_dev_ring_ctx *ctx,
|
|||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
return rc;
|
||||
|
||||
cleanup:
|
||||
dma_free_coherent(mhi->dev,
|
||||
ring->ring_size *
|
||||
sizeof(union mhi_dev_ring_element_type),
|
||||
ring->ring_cache,
|
||||
ring->ring_cache_dma_handle);
|
||||
ring->ring_cache = NULL;
|
||||
if (ring->evt_rp_cache) {
|
||||
dma_free_coherent(mhi->dev,
|
||||
sizeof(uint64_t) * ring->ring_size,
|
||||
ring->evt_rp_cache,
|
||||
ring->evt_rp_cache_dma_handle);
|
||||
ring->evt_rp_cache = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(mhi_ring_start);
|
||||
|
|
|
|||
Loading…
Reference in a new issue