summaryrefslogtreecommitdiff
path: root/drivers/platform/msm
diff options
context:
space:
mode:
authorTony Truong <truong@codeaurora.org>2015-07-31 12:42:44 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 21:24:42 -0700
commit39e32e5185a32adfb90b2cf915c92cf11cb16c1f (patch)
treeb3f9a4e3ee58b26538f59f1544f271600228383e /drivers/platform/msm
parentf688e16bf59fe323d83c4067125f9eaeebfb7906 (diff)
mhi: core: Enable parsing of dev window from dt
Enable parsing of device window size from device tree and calculating the appropriate addressing limitations. Change-Id: I252a593a74f0cc00e6295a45d4d13db6c79cdfca Signed-off-by: Andrei Danaila <adanaila@codeaurora.org> Signed-off-by: Tony Truong <truong@codeaurora.org>
Diffstat (limited to 'drivers/platform/msm')
-rw-r--r--drivers/platform/msm/mhi/mhi.h6
-rw-r--r--drivers/platform/msm/mhi/mhi_init.c84
2 files changed, 73 insertions, 17 deletions
diff --git a/drivers/platform/msm/mhi/mhi.h b/drivers/platform/msm/mhi/mhi.h
index 7d55b6781f76..588f91a93e12 100644
--- a/drivers/platform/msm/mhi/mhi.h
+++ b/drivers/platform/msm/mhi/mhi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -441,8 +441,8 @@ struct mhi_dev_space {
dma_addr_t dma_dev_mem_start;
size_t dev_mem_len;
struct mhi_ring_ctxt ring_ctxt;
- dma_addr_t start_win_addr;
- dma_addr_t end_win_addr;
+ u64 start_win_addr;
+ u64 end_win_addr;
};
struct mhi_device_ctxt {
diff --git a/drivers/platform/msm/mhi/mhi_init.c b/drivers/platform/msm/mhi/mhi_init.c
index 15ef91fae4df..e6a90be6b760 100644
--- a/drivers/platform/msm/mhi/mhi_init.c
+++ b/drivers/platform/msm/mhi/mhi_init.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
#include <linux/cpu.h>
#include <linux/kthread.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <linux/completion.h>
#include <linux/platform_device.h>
@@ -214,15 +215,54 @@ static int enable_bb_ctxt(struct mhi_ring *bb_ctxt, int nr_el)
return 0;
}
-static void calculate_mhi_addressing_window(
- struct mhi_device_ctxt *mhi_dev_ctxt)
+/*
+ * The device can have severe addressing limitations, and in this case
+ * the MHI driver may be restricted on where memory can be allocated.
+ *
+ * The allocation of the MHI control data structures takes place as one
+ * big, physically contiguous allocation.
+ * The device's addressing window, must be placed around that control segment
+ * allocation.
+ * Here we attempt to do this by building an addressing window around the
+ * initial allocated control segment.
+ *
+ * The window size is specified by the device and must be contiguous,
+ * but depending on where the control segment was allocated, it may be
+ * necessary to leave more room, before the ctrl segment start or after
+ * the ctrl segment end.
+ * The following assumptions are made:
+ * Assumption: 1. size of allocated ctrl seg << (device allocation window / 2)
+ * 2. allocated ctrl seg is physically contiguous
+ */
+static int calculate_mhi_addressing_window(struct mhi_device_ctxt *mhi_dev_ctxt)
{
- dma_addr_t dma_dev_mem_start;
- dma_addr_t dma_seg_size = 0x1FF00000UL;
- dma_addr_t dma_max_addr = (dma_addr_t)(-1);
+ u64 dma_dev_mem_start = 0;
+ u64 dma_seg_size = 0;
+ u64 dma_max_addr = (dma_addr_t)(-1);
+ u64 dev_address_limit = 0;
+ int r = 0;
+ const struct device_node *np =
+ mhi_dev_ctxt->dev_info->plat_dev->dev.of_node;
dma_dev_mem_start = mhi_dev_ctxt->dev_space.dma_dev_mem_start;
-
+ r = of_property_read_u64(np, "mhi-dev-address-win-size",
+ &dev_address_limit);
+ if (r) {
+ mhi_log(MHI_MSG_ERROR,
+ "Failed to get device addressing limit ret %d",
+ r);
+ return r;
+ }
+ /* Mask off the last 3 bits for address calculation */
+ dev_address_limit &= ~0x7;
+ mhi_log(MHI_MSG_INFO, "Device Addressing limit 0x%llx\n",
+ dev_address_limit);
+ dma_seg_size = dev_address_limit / 2;
+
+ /*
+ * The region of the allocated control segment is within the
+ * first half of the device's addressing limit
+ */
if (dma_dev_mem_start < dma_seg_size) {
mhi_dev_ctxt->dev_space.start_win_addr = 0;
mhi_dev_ctxt->dev_space.end_win_addr =
@@ -230,15 +270,26 @@ static void calculate_mhi_addressing_window(
(dma_seg_size - dma_dev_mem_start);
} else if (dma_dev_mem_start >= dma_seg_size &&
dma_dev_mem_start <= (dma_max_addr - dma_seg_size)) {
+ /*
+ * The start of the control segment is located past
+ * halfway point of the device's addressing limit
+ * Place the control segment in the middle of the device's
+ * addressing range
+ */
mhi_dev_ctxt->dev_space.start_win_addr =
dma_dev_mem_start - dma_seg_size;
mhi_dev_ctxt->dev_space.end_win_addr =
dma_dev_mem_start + dma_seg_size;
} else if (dma_dev_mem_start > (dma_max_addr - dma_seg_size)) {
- mhi_dev_ctxt->dev_space.start_win_addr =
- dma_dev_mem_start - (dma_seg_size +
- (dma_seg_size - (dma_max_addr -
- dma_dev_mem_start)));
+ /*
+ * The start of the control segment is located at the tail end
+ * of the host addressing space. Leave extra addressing space
+ * at window start
+ */
+ mhi_dev_ctxt->dev_space.start_win_addr = dma_dev_mem_start;
+ mhi_dev_ctxt->dev_space.start_win_addr -=
+ dma_seg_size + (dma_seg_size -
+ (dma_max_addr - dma_dev_mem_start));
mhi_dev_ctxt->dev_space.end_win_addr = dma_max_addr;
}
mhi_log(MHI_MSG_INFO,
@@ -246,7 +297,7 @@ static void calculate_mhi_addressing_window(
(u64)dma_dev_mem_start,
(u64)mhi_dev_ctxt->dev_space.start_win_addr,
(u64)mhi_dev_ctxt->dev_space.end_win_addr);
-
+ return 0;
}
int init_mhi_dev_mem(struct mhi_device_ctxt *mhi_dev_ctxt)
@@ -274,7 +325,12 @@ int init_mhi_dev_mem(struct mhi_device_ctxt *mhi_dev_ctxt)
dma_dev_mem_start = mhi_dev_ctxt->dev_space.dma_dev_mem_start;
memset(dev_mem_start, 0, mhi_dev_ctxt->dev_space.dev_mem_len);
- calculate_mhi_addressing_window(mhi_dev_ctxt);
+ r = calculate_mhi_addressing_window(mhi_dev_ctxt);
+ if (r) {
+ mhi_log(MHI_MSG_ERROR,
+ "Failed to calculate addressing window ret %d", r);
+ return r;
+ }
mhi_log(MHI_MSG_INFO, "Starting Seg address: virt 0x%p, dma 0x%llx\n",
dev_mem_start, (u64)dma_dev_mem_start);
@@ -441,7 +497,7 @@ error_state_change_event_handle:
kfree(mhi_dev_ctxt->mhi_ev_wq.state_change_event);
error_event_handle_alloc:
kfree(mhi_dev_ctxt->mhi_ev_wq.mhi_event_wq);
- return MHI_STATUS_ERROR;
+ return -ENOMEM;
}
static int mhi_init_state_change_thread_work_queue(