When using default memory for coherent memory allocation without
reservation, memory gets fragmented after several mhi
register/unregister cycles and no coherent reservation was possible.
Client driver registering MHI shall reserve a dedicated region as
shared-dma-pool for mhi to help avoid this situation. On boards
which doesn't reserve this memory, it will continue to allocate
memory from default memory.
DMA pool is reserved for coherent allocations of size SZ_512K
(mhi_cntrl->seg_len) to avoid fragmentation and always ensure
allocations of SZ_512K succeeds. Allocations of lower order from the
reserved memory would lead to fragmentation on multiple alloc/frees.
So use dma_alloc_coherent from mhi_cntrl->cntrl_dev for allocations
lower than mhi_cntrl->seg_len. If coherent pool is not reserved, all
reservations go through mhi_cntrl->cntrl_dev.
Co-developed-by: Vignesh Viswanathan <quic_viswanat@xxxxxxxxxxx>
Signed-off-by: Vignesh Viswanathan <quic_viswanat@xxxxxxxxxxx>
Signed-off-by: Gokul Sriram Palanisamy <quic_gokulsri@xxxxxxxxxxx>
---
drivers/bus/mhi/host/boot.c | 19 ++++++------
drivers/bus/mhi/host/init.c | 51 +++++++++++++++++++++++++++++++++
drivers/bus/mhi/host/internal.h | 26 +++++++++++++++++
include/linux/mhi.h | 5 ++++
4 files changed, 91 insertions(+), 10 deletions(-)
diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c
index dedd29ca8db3..ca842facf820 100644
--- a/drivers/bus/mhi/host/boot.c
+++ b/drivers/bus/mhi/host/boot.c
@@ -303,8 +303,8 @@ void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl,
struct mhi_buf *mhi_buf = image_info->mhi_buf;
for (i = 0; i < image_info->entries; i++, mhi_buf++)
- dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len,
- mhi_buf->buf, mhi_buf->dma_addr);
+ mhi_fw_free_coherent(mhi_cntrl, mhi_buf->len,
+ mhi_buf->buf, mhi_buf->dma_addr);
kfree(image_info->mhi_buf);
kfree(image_info);
@@ -340,9 +340,9 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl,
vec_size = sizeof(struct bhi_vec_entry) * i;
mhi_buf->len = vec_size;
- mhi_buf->buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev,
- vec_size, &mhi_buf->dma_addr,
- GFP_KERNEL);
+ mhi_buf->buf = mhi_fw_alloc_coherent(mhi_cntrl, vec_size,
+ &mhi_buf->dma_addr,
+ GFP_KERNEL);
if (!mhi_buf->buf)
goto error_alloc_segment;
}
@@ -355,8 +355,8 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl,
error_alloc_segment:
for (--i, --mhi_buf; i >= 0; i--, mhi_buf--)
- dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len,
- mhi_buf->buf, mhi_buf->dma_addr);
+ mhi_fw_free_coherent(mhi_cntrl, mhi_buf->len,
+ mhi_buf->buf, mhi_buf->dma_addr);
error_alloc_mhi_buf:
kfree(img_info);
@@ -452,8 +452,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
fw_sz = firmware->size;
skip_req_fw:
- buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, &dma_addr,
- GFP_KERNEL);
+ buf = mhi_fw_alloc_coherent(mhi_cntrl, size, &dma_addr, GFP_KERNEL);
if (!buf) {
release_firmware(firmware);
goto error_fw_load;
@@ -462,7 +461,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
/* Download image using BHI */
memcpy(buf, fw_data, size);
ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size);
- dma_free_coherent(mhi_cntrl->cntrl_dev, size, buf, dma_addr);
+ mhi_fw_free_coherent(mhi_cntrl, size, buf, dma_addr);
/* Error or in EDL mode, we're done */
if (ret) {
diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c
index ce7d2e62c2f1..c1e1412c43e2 100644
--- a/drivers/bus/mhi/host/init.c
+++ b/drivers/bus/mhi/host/init.c
@@ -8,9 +8,12 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/dma-direction.h>
+#include <linux/dma-map-ops.h>
#include <linux/dma-mapping.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_reserved_mem.h>