From 9356633195f058e7d4d42f6d4c00dc7fd1e18629 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Wed, 8 Jan 2020 18:51:41 -0800 Subject: [PATCH] mhi: core: Add support to create uncached event ring This helps to selectively mark an event ring as uncached to debug cache-coherency issue. Change-Id: I25a1310df0576496af9e1fb624ec8c54c670dfe8 Signed-off-by: Hemant Kumar --- drivers/bus/mhi/core/mhi_init.c | 38 ++++++++++++++++++++++++++--- drivers/bus/mhi/core/mhi_internal.h | 24 ++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 30005f38e37c..5b37cd32e0f8 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -223,6 +223,21 @@ static int mhi_alloc_aligned_ring(struct mhi_controller *mhi_cntrl, return 0; } +/* MHI protocol require transfer ring to be aligned to ring length */ +static int mhi_alloc_aligned_ring_uncached( + struct mhi_controller *mhi_cntrl, struct mhi_ring *ring, u64 len) +{ + ring->alloc_size = len + (len - 1); + ring->pre_aligned = mhi_alloc_uncached(mhi_cntrl, ring->alloc_size, + &ring->dma_handle, GFP_KERNEL); + if (!ring->pre_aligned) + return -ENOMEM; + + ring->iommu_base = (ring->dma_handle + (len - 1)) & ~(len - 1); + ring->base = ring->pre_aligned + (ring->iommu_base - ring->dma_handle); + return 0; +} + void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl) { int i; @@ -307,7 +322,11 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl) continue; ring = &mhi_event->ring; - mhi_free_coherent(mhi_cntrl, ring->alloc_size, + if (mhi_event->force_uncached) + mhi_free_uncached(mhi_cntrl, ring->alloc_size, + ring->pre_aligned, ring->dma_handle); + else + mhi_free_coherent(mhi_cntrl, ring->alloc_size, ring->pre_aligned, ring->dma_handle); ring->base = NULL; ring->iommu_base = 0; @@ -463,7 +482,12 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl) ring->el_size = sizeof(struct mhi_tre); ring->len = ring->el_size * ring->elements; - ret = mhi_alloc_aligned_ring(mhi_cntrl, ring, ring->len); + if (mhi_event->force_uncached) + ret = mhi_alloc_aligned_ring_uncached(mhi_cntrl, ring, + ring->len); + else + ret = mhi_alloc_aligned_ring(mhi_cntrl, ring, + ring->len); if (ret) goto error_alloc_er; @@ -524,7 +548,11 @@ error_alloc_er: if (mhi_event->offload_ev) continue; - mhi_free_coherent(mhi_cntrl, ring->alloc_size, + if (mhi_event->force_uncached) + mhi_free_uncached(mhi_cntrl, ring->alloc_size, + ring->pre_aligned, ring->dma_handle); + else + mhi_free_coherent(mhi_cntrl, ring->alloc_size, ring->pre_aligned, ring->dma_handle); } mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->er_ctxt) * @@ -988,6 +1016,10 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl, continue; mhi_event->er_index = i++; + + mhi_event->force_uncached = of_property_read_bool(child, + "mhi,force-uncached"); + ret = of_property_read_u32(child, "mhi,num-elements", (u32 *)&mhi_event->ring.elements); if (ret) diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index f77f6fa9865e..c43d1a3b485d 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -656,6 +656,7 @@ struct mhi_event { struct mhi_controller *mhi_cntrl; struct mhi_tre last_cached_tre; u64 last_dev_rp; + bool force_uncached; }; struct mhi_chan { @@ -853,6 +854,29 @@ static inline void mhi_free_coherent(struct mhi_controller *mhi_cntrl, dma_free_coherent(mhi_cntrl->dev, size, vaddr, dma_handle); } +static inline void *mhi_alloc_uncached(struct mhi_controller *mhi_cntrl, + size_t size, + dma_addr_t *dma_handle, + gfp_t gfp) +{ + void *buf = dma_alloc_attrs(mhi_cntrl->dev, size, dma_handle, gfp, + DMA_ATTR_FORCE_NON_COHERENT); + + if (buf) + atomic_add(size, &mhi_cntrl->alloc_size); + + return buf; +} +static inline void mhi_free_uncached(struct mhi_controller *mhi_cntrl, + size_t size, + void *vaddr, + dma_addr_t dma_handle) +{ + atomic_sub(size, &mhi_cntrl->alloc_size); + dma_free_attrs(mhi_cntrl->dev, size, vaddr, dma_handle, + DMA_ATTR_FORCE_NON_COHERENT); +} + static inline void *mhi_alloc_contig_coherent( struct mhi_controller *mhi_cntrl, size_t size, dma_addr_t *dma_handle,