// SPDX-License-Identifier: GPL-2.0
/*
* Cadence CDNSP DRD Driver.
*
* Copyright (C) 2020 Cadence.
*
* Author: Pawel Laszczak <pawell@cadence.com>
*
* Code based on Linux XHCI driver.
* Origin: Copyright (C) 2008 Intel Corp.
*/
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include "cdnsp-gadget.h"
#include "cdnsp-trace.h"
static void cdnsp_free_stream_info(struct cdnsp_device *pdev,
struct cdnsp_ep *pep);
/*
* 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.
*
* "All components of all Command and Transfer TRBs shall be initialized to '0'"
*/
static struct cdnsp_segment *cdnsp_segment_alloc(struct cdnsp_device *pdev,
unsigned int cycle_state,
unsigned int max_packet,
gfp_t flags)
{
struct cdnsp_segment *seg;
dma_addr_t dma;
int i;
seg = kzalloc(sizeof(*seg), flags);
if (!seg)
return NULL;
seg->trbs = dma_pool_zalloc(pdev->segment_pool, flags, &dma);
if (!seg->trbs) {
kfree(seg);
return NULL;
}
if (max_packet) {
seg->bounce_buf = kzalloc(max_packet, flags | GFP_DMA);
if (!seg->bounce_buf)
goto free_dma;
}
/* If the cycle state is 0, set the cycle bit to 1 for all the TRBs. */
if (cycle_state == 0) {
for (i = 0; i < TRBS_PER_SEGMENT; i++)
seg->trbs[i].link.control |= cpu_to_le32(TRB_CYCLE);
}
seg->dma = dma;
seg->next = NULL;
return seg;
free_dma:
dma_pool_free(pdev->segment_pool, seg->trbs, dma);
kfree(seg);
return NULL;
}
static void cdnsp_segment_free(struct cdnsp_device *pdev,
struct cdnsp_segment *seg)
{
if (seg->trbs)
dma_pool_free(pdev->segment_pool, seg->trbs, seg->dma);
kfree(seg->bounce_buf);
kfree(seg);
}
static void cdnsp_free_segments_for_ring(struct cdnsp_device *pdev,
struct cdnsp_segment *first)
{
struct cdnsp_segment *seg;
seg = first->next;
while (seg != first) {
struct cdnsp_segment *next = seg->next;
cdnsp_segment_free(pdev, seg);
seg = next;
}
cdnsp_segment_free(pdev, first);
}
/*
* Make the prev segment point to t