linux/drivers/usb/cdns3/cdnsp-mem.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Cadence CDNSP DRD Driver.
 *
 * Copyright (C) 2020 Cadence.
 *
 * Author: Pawel Laszczak <[email protected]>
 *
 * 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)
{}

static void cdnsp_segment_free(struct cdnsp_device *pdev,
			       struct cdnsp_segment *seg)
{}

static void cdnsp_free_segments_for_ring(struct cdnsp_device *pdev,
					 struct cdnsp_segment *first)
{}

/*
 * Make the prev segment point to the next segment.
 *
 * Change the last TRB in the prev segment to be a Link TRB which points to the
 * DMA address of the next segment. The caller needs to set any Link TRB
 * related flags, such as End TRB, Toggle Cycle, and no snoop.
 */
static void cdnsp_link_segments(struct cdnsp_device *pdev,
				struct cdnsp_segment *prev,
				struct cdnsp_segment *next,
				enum cdnsp_ring_type type)
{}

/*
 * Link the ring to the new segments.
 * Set Toggle Cycle for the new ring if needed.
 */
static void cdnsp_link_rings(struct cdnsp_device *pdev,
			     struct cdnsp_ring *ring,
			     struct cdnsp_segment *first,
			     struct cdnsp_segment *last,
			     unsigned int num_segs)
{}

/*
 * We need a radix tree for mapping physical addresses of TRBs to which stream
 * ID they belong to. We need to do this because the device controller won't
 * tell us which stream ring the TRB came from. We could store the stream ID
 * in an event data TRB, but that doesn't help us for the cancellation case,
 * since the endpoint may stop before it reaches that event data TRB.
 *
 * The radix tree maps the upper portion of the TRB DMA address to a ring
 * segment that has the same upper portion of DMA addresses. For example,
 * say I have segments of size 1KB, that are always 1KB aligned. A segment may
 * start at 0x10c91000 and end at 0x10c913f0. If I use the upper 10 bits, the
 * key to the stream ID is 0x43244. I can use the DMA address of the TRB to
 * pass the radix tree a key to get the right stream ID:
 *
 *	0x10c90fff >> 10 = 0x43243
 *	0x10c912c0 >> 10 = 0x43244
 *	0x10c91400 >> 10 = 0x43245
 *
 * Obviously, only those TRBs with DMA addresses that are within the segment
 * will make the radix tree return the stream ID for that ring.
 *
 * Caveats for the radix tree:
 *
 * The radix tree uses an unsigned long as a key pair. On 32-bit systems, an
 * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be
 * 64-bits. Since we only request 32-bit DMA addresses, we can use that as the
 * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit
 * PCI DMA addresses on a 64-bit system). There might be a problem on 32-bit
 * extended systems (where the DMA address can be bigger than 32-bits),
 * if we allow the PCI dma mask to be bigger than 32-bits. So don't do that.
 */
static int cdnsp_insert_segment_mapping(struct radix_tree_root *trb_address_map,
					struct cdnsp_ring *ring,
					struct cdnsp_segment *seg,
					gfp_t mem_flags)
{}

static void cdnsp_remove_segment_mapping(struct radix_tree_root *trb_address_map,
					 struct cdnsp_segment *seg)
{}

static int cdnsp_update_stream_segment_mapping(struct radix_tree_root *trb_address_map,
					       struct cdnsp_ring *ring,
					       struct cdnsp_segment *first_seg,
					       struct cdnsp_segment *last_seg,
					       gfp_t mem_flags)
{}

static void cdnsp_remove_stream_mapping(struct cdnsp_ring *ring)
{}

static int cdnsp_update_stream_mapping(struct cdnsp_ring *ring)
{}

static void cdnsp_ring_free(struct cdnsp_device *pdev, struct cdnsp_ring *ring)
{}

void cdnsp_initialize_ring_info(struct cdnsp_ring *ring)
{}

/* Allocate segments and link them for a ring. */
static int cdnsp_alloc_segments_for_ring(struct cdnsp_device *pdev,
					 struct cdnsp_segment **first,
					 struct cdnsp_segment **last,
					 unsigned int num_segs,
					 unsigned int cycle_state,
					 enum cdnsp_ring_type type,
					 unsigned int max_packet,
					 gfp_t flags)
{}

/*
 * Create a new ring with zero or more segments.
 *
 * Link each segment together into a ring.
 * Set the end flag and the cycle toggle bit on the last segment.
 */
static struct cdnsp_ring *cdnsp_ring_alloc(struct cdnsp_device *pdev,
					   unsigned int num_segs,
					   enum cdnsp_ring_type type,
					   unsigned int max_packet,
					   gfp_t flags)
{}

void cdnsp_free_endpoint_rings(struct cdnsp_device *pdev, struct cdnsp_ep *pep)
{}

/*
 * Expand an existing ring.
 * Allocate a new ring which has same segment numbers and link the two rings.
 */
int cdnsp_ring_expansion(struct cdnsp_device *pdev,
			 struct cdnsp_ring *ring,
			 unsigned int num_trbs,
			 gfp_t flags)
{}

static int cdnsp_init_device_ctx(struct cdnsp_device *pdev)
{}

struct cdnsp_input_control_ctx
	*cdnsp_get_input_control_ctx(struct cdnsp_container_ctx *ctx)
{}

struct cdnsp_slot_ctx *cdnsp_get_slot_ctx(struct cdnsp_container_ctx *ctx)
{}

struct cdnsp_ep_ctx *cdnsp_get_ep_ctx(struct cdnsp_container_ctx *ctx,
				      unsigned int ep_index)
{}

static void cdnsp_free_stream_ctx(struct cdnsp_device *pdev,
				  struct cdnsp_ep *pep)
{}

/* The stream context array must be a power of 2. */
static struct cdnsp_stream_ctx
	*cdnsp_alloc_stream_ctx(struct cdnsp_device *pdev, struct cdnsp_ep *pep)
{}

struct cdnsp_ring *cdnsp_dma_to_transfer_ring(struct cdnsp_ep *pep, u64 address)
{}

/*
 * Change an endpoint's internal structure so it supports stream IDs.
 * The number of requested streams includes stream 0, which cannot be used by
 * driver.
 *
 * The number of stream contexts in the stream context array may be bigger than
 * the number of streams the driver wants to use. This is because the number of
 * stream context array entries must be a power of two.
 */
int cdnsp_alloc_stream_info(struct cdnsp_device *pdev,
			    struct cdnsp_ep *pep,
			    unsigned int num_stream_ctxs,
			    unsigned int num_streams)
{}

/* Frees all stream contexts associated with the endpoint. */
static void cdnsp_free_stream_info(struct cdnsp_device *pdev,
				   struct cdnsp_ep *pep)
{}

/* All the cdnsp_tds in the ring's TD list should be freed at this point.*/
static void cdnsp_free_priv_device(struct cdnsp_device *pdev)
{}

static int cdnsp_alloc_priv_device(struct cdnsp_device *pdev)
{}

void cdnsp_copy_ep0_dequeue_into_input_ctx(struct cdnsp_device *pdev)
{}

/* Setup an controller private device for a Set Address command. */
int cdnsp_setup_addressable_priv_dev(struct cdnsp_device *pdev)
{}

/*
 * Convert interval expressed as 2^(bInterval - 1) == interval into
 * straight exponent value 2^n == interval.
 */
static unsigned int cdnsp_parse_exponent_interval(struct usb_gadget *g,
						  struct cdnsp_ep *pep)
{}

/*
 * Convert bInterval expressed in microframes (in 1-255 range) to exponent of
 * microframes, rounded down to nearest power of 2.
 */
static unsigned int cdnsp_microframes_to_exponent(struct usb_gadget *g,
						  struct cdnsp_ep *pep,
						  unsigned int desc_interval,
						  unsigned int min_exponent,
						  unsigned int max_exponent)
{}

/*
 * Return the polling interval.
 *
 * The polling interval is expressed in "microframes". If controllers's Interval
 * field is set to N, it will service the endpoint every 2^(Interval)*125us.
 */
static unsigned int cdnsp_get_endpoint_interval(struct usb_gadget *g,
						struct cdnsp_ep *pep)
{}

/*
 * The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps.
 * High speed endpoint descriptors can define "the number of additional
 * transaction opportunities per microframe", but that goes in the Max Burst
 * endpoint context field.
 */
static u32 cdnsp_get_endpoint_mult(struct usb_gadget *g, struct cdnsp_ep *pep)
{}

static u32 cdnsp_get_endpoint_max_burst(struct usb_gadget *g,
					struct cdnsp_ep *pep)
{}

static u32 cdnsp_get_endpoint_type(const struct usb_endpoint_descriptor *desc)
{}

/*
 * Return the maximum endpoint service interval time (ESIT) payload.
 * Basically, this is the maxpacket size, multiplied by the burst size
 * and mult size.
 */
static u32 cdnsp_get_max_esit_payload(struct usb_gadget *g,
				      struct cdnsp_ep *pep)
{}

int cdnsp_endpoint_init(struct cdnsp_device *pdev,
			struct cdnsp_ep *pep,
			gfp_t mem_flags)
{}

void cdnsp_endpoint_zero(struct cdnsp_device *pdev, struct cdnsp_ep *pep)
{}

static int cdnsp_alloc_erst(struct cdnsp_device *pdev,
			    struct cdnsp_ring *evt_ring,
			    struct cdnsp_erst *erst)
{}

static void cdnsp_free_erst(struct cdnsp_device *pdev, struct cdnsp_erst *erst)
{}

void cdnsp_mem_cleanup(struct cdnsp_device *pdev)
{}

static void cdnsp_set_event_deq(struct cdnsp_device *pdev)
{}

static void cdnsp_add_in_port(struct cdnsp_device *pdev,
			      struct cdnsp_port *port,
			      __le32 __iomem *addr)
{}

/*
 * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that
 * specify what speeds each port is supposed to be.
 */
static int cdnsp_setup_port_arrays(struct cdnsp_device *pdev)
{}

/*
 * Initialize memory for CDNSP (one-time init).
 *
 * Program the PAGESIZE register, initialize the device context array, create
 * device contexts, set up a command ring segment, create event
 * ring (one for now).
 */
int cdnsp_mem_init(struct cdnsp_device *pdev)
{}