#include <linux/slab.h>
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
+#include <linux/types.h>
#include "xhci.h"
+#include "xhci-plat.h"
#include "xhci-trace.h"
+static void *dma_pre_alloc_coherent(struct xhci_hcd *xhci, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
+{
+ struct usb_xhci_pre_alloc *xhci_alloc = xhci->xhci_alloc;
+ u64 align = size % PAGE_SIZE;
+ u64 b_offset = xhci_alloc->offset;
+
+ if (align)
+ xhci_alloc->offset = xhci_alloc->offset + size + (PAGE_SIZE - align);
+ else
+ xhci_alloc->offset = xhci_alloc->offset + size;
+
+ *dma_handle = xhci_alloc->dma + b_offset;
+
+ return (void *)xhci_alloc->pre_dma_alloc + b_offset;
+}
+
/*
* Allocates a generic ring segment from the ring pool, sets the dma address,
* initializes the segment to zero, and sets the private next pointer to NULL.
unsigned int num_stream_ctxs,
struct xhci_stream_ctx *stream_ctx, dma_addr_t dma)
{
- struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
- if (size > MEDIUM_STREAM_ARRAY_SIZE)
- dma_free_coherent(dev, size,
- stream_ctx, dma);
- else if (size <= SMALL_STREAM_ARRAY_SIZE)
+ if (size <= SMALL_STREAM_ARRAY_SIZE)
return dma_pool_free(xhci->small_streams_pool,
stream_ctx, dma);
else
unsigned int num_stream_ctxs, dma_addr_t *dma,
gfp_t mem_flags)
{
- struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
if (size > MEDIUM_STREAM_ARRAY_SIZE)
- return dma_alloc_coherent(dev, size,
+ return dma_pre_alloc_coherent(xhci, size,
dma, mem_flags);
else if (size <= SMALL_STREAM_ARRAY_SIZE)
return dma_pool_alloc(xhci->small_streams_pool,
static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
{
int i;
- struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
if (!xhci->scratchpad)
goto fail_sp;
- xhci->scratchpad->sp_array = dma_alloc_coherent(dev,
+ xhci->scratchpad->sp_array = dma_pre_alloc_coherent(xhci,
num_sp * sizeof(u64),
&xhci->scratchpad->sp_dma, flags);
if (!xhci->scratchpad->sp_array)
xhci->scratchpad->sp_buffers = kzalloc(sizeof(void *) * num_sp, flags);
if (!xhci->scratchpad->sp_buffers)
- goto fail_sp3;
+ goto fail_sp2;
xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma);
for (i = 0; i < num_sp; i++) {
dma_addr_t dma;
- void *buf = dma_zalloc_coherent(dev, xhci->page_size, &dma,
- flags);
+ void *buf = dma_pre_alloc_coherent(xhci, xhci->page_size, &dma,
+ flags | __GFP_ZERO);
if (!buf)
goto fail_sp4;
return 0;
fail_sp4:
- for (i = i - 1; i >= 0; i--) {
- dma_free_coherent(dev, xhci->page_size,
- xhci->scratchpad->sp_buffers[i],
- xhci->scratchpad->sp_array[i]);
- }
-
kfree(xhci->scratchpad->sp_buffers);
- fail_sp3:
- dma_free_coherent(dev, num_sp * sizeof(u64),
- xhci->scratchpad->sp_array,
- xhci->scratchpad->sp_dma);
-
fail_sp2:
kfree(xhci->scratchpad);
xhci->scratchpad = NULL;
static void scratchpad_free(struct xhci_hcd *xhci)
{
int num_sp;
- int i;
- struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
if (!xhci->scratchpad)
return;
num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
- for (i = 0; i < num_sp; i++) {
- dma_free_coherent(dev, xhci->page_size,
- xhci->scratchpad->sp_buffers[i],
- xhci->scratchpad->sp_array[i]);
- }
kfree(xhci->scratchpad->sp_buffers);
- dma_free_coherent(dev, num_sp * sizeof(u64),
- xhci->scratchpad->sp_array,
- xhci->scratchpad->sp_dma);
+
kfree(xhci->scratchpad);
xhci->scratchpad = NULL;
}
void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
- struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
- int size;
int i, j, num_ports;
cancel_delayed_work_sync(&xhci->cmd_timer);
- /* Free the Event Ring Segment Table and the actual Event Ring */
- size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
- if (xhci->erst.entries)
- dma_free_coherent(dev, size,
- xhci->erst.entries, xhci->erst.erst_dma_addr);
xhci->erst.entries = NULL;
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed ERST");
if (xhci->event_ring)
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring");
#ifdef CONFIG_SND_EXYNOS_USB_AUDIO
- if (xhci->save_addr)
- dma_free_coherent(dev, sizeof(PAGE_SIZE), xhci->save_addr, xhci->save_dma);
- xhci_info(xhci, "%s: Freed save-restore buffer for Audio offloading", __func__);
-
- size = sizeof(struct xhci_erst_entry)*(xhci->erst_audio.num_entries);
- if (xhci->erst_audio.entries)
- dma_free_coherent(dev, size,
- xhci->erst_audio.entries, xhci->erst_audio.erst_dma_addr);
xhci->erst_audio.entries = NULL;
xhci_info(xhci, "%s: Freed ERST for Audio offloading", __func__);
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Freed medium stream array pool");
- if (xhci->dcbaa)
- dma_free_coherent(dev, sizeof(*xhci->dcbaa),
- xhci->dcbaa, xhci->dcbaa->dma);
xhci->dcbaa = NULL;
+ /* init offset about pre alloc CMA */
+ xhci->xhci_alloc->offset = 0;
+
scratchpad_free(xhci);
if (!xhci->rh_bw)
* xHCI section 5.4.6 - doorbell array must be
* "physically contiguous and 64-byte (cache line) aligned".
*/
- xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma,
+ xhci->dcbaa = dma_pre_alloc_coherent(xhci, sizeof(*xhci->dcbaa), &dma,
flags);
if (!xhci->dcbaa)
goto fail;
if (xhci_check_trb_in_td_math(xhci) < 0)
goto fail;
- xhci->erst.entries = dma_alloc_coherent(dev,
+ xhci->erst.entries = dma_pre_alloc_coherent(xhci,
sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS, &dma,
flags);
if (!xhci->erst.entries)
xhci_print_ir_set(xhci, 0);
#ifdef CONFIG_SND_EXYNOS_USB_AUDIO
- xhci->save_addr = dma_alloc_coherent(dev, sizeof(PAGE_SIZE), &dma,
+ xhci->save_addr = dma_pre_alloc_coherent(xhci, sizeof(PAGE_SIZE), &dma,
flags);
xhci->save_dma = dma;
xhci_info(xhci, "// Save address = 0x%llx (DMA), %p (virt)",
if (xhci_check_trb_in_td_math(xhci) < 0)
goto fail;
- xhci->erst_audio.entries = dma_alloc_coherent(dev,
+ xhci->erst_audio.entries = dma_pre_alloc_coherent(xhci,
sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS, &dma,
flags);
if (!xhci->erst_audio.entries)