Merge "msm: sps: Add SPS driver snapshot"

This commit is contained in:
qctecmdr 2019-12-18 21:53:38 -08:00 • committed by Gerrit - the friendly Code Review server
commit 4837fa24d4
16 changed files with 13225 additions and 0 deletions

View file

@ -3,6 +3,35 @@
menu "Qualcomm technologies inc. MSM specific device drivers"
depends on ARCH_QCOM
config SPS
tristate "SPS support"
select GENERIC_ALLOCATOR
help
The SPS (Smart Peripheral Switch) is a DMA engine.
It can move data in the following modes:
1. Peripheral-to-Peripheral.
2. Peripheral-to-Memory.
3. Memory-to-Memory.
config SPS_SUPPORT_BAMDMA
bool "SPS supports BAM DMA"
depends on SPS
help
The BAM-DMA is used for Memory-to-Memory transfers.
The main use cases is RPC between processors.
The BAM-DMA hardware has 2 registers sets:
1. A BAM HW like all the peripherals.
2. A DMA channel configuration (i.e. channel priority).
config SPS_SUPPORT_NDP_BAM
bool "SPS supports NDP BAM"
depends on SPS
help
No-Data-Path BAM is used to improve BAM performance.
NDP BAMs enables peripherals with fast fabric connectivity
to do the actual data transfer themselves, instead of the
BAM.
config GSI
tristate "GSI support"
help

View file

@ -8,3 +8,4 @@ obj-$(CONFIG_IPA3) += ipa/
obj-$(CONFIG_MSM_GENI_SE) += msm-geni-se.o
obj-$(CONFIG_USB_BAM) += usb_bam.o
obj-$(CONFIG_QPNP_REVID) += qpnp-revid.o
obj-$(CONFIG_SPS) += sps/

View file

@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
# Makefile for SPS BAM driver
#
obj-$(CONFIG_SPS) += sps_drv.o
sps_drv-objs := bam.o sps_bam.o sps.o sps_dma.o sps_map.o sps_mem.o sps_rm.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,439 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved.
*/
/* Bus-Access-Manager (BAM) Hardware manager functions API. */
#ifndef _BAM_H_
#define _BAM_H_
#include <linux/types.h> /* u32 */
#include <linux/io.h> /* ioread32() */
#include <linux/bitops.h> /* find_first_bit() */
#include "spsi.h"
/* Pipe mode */
enum bam_pipe_mode {
BAM_PIPE_MODE_BAM2BAM = 0, /* BAM to BAM */
BAM_PIPE_MODE_SYSTEM = 1, /* BAM to/from System Memory */
};
/* Pipe direction */
enum bam_pipe_dir {
/* The Pipe Reads data from data-fifo or system-memory */
BAM_PIPE_CONSUMER = 0,
/* The Pipe Writes data to data-fifo or system-memory */
BAM_PIPE_PRODUCER = 1,
};
/* Stream mode Type */
enum bam_stream_mode {
BAM_STREAM_MODE_DISABLE = 0,
BAM_STREAM_MODE_ENABLE = 1,
};
/* NWD written Type */
enum bam_write_nwd {
BAM_WRITE_NWD_DISABLE = 0,
BAM_WRITE_NWD_ENABLE = 1,
};
/* Enable Type */
enum bam_enable {
BAM_DISABLE = 0,
BAM_ENABLE = 1,
};
/* Pipe timer mode */
enum bam_pipe_timer_mode {
BAM_PIPE_TIMER_ONESHOT = 0,
BAM_PIPE_TIMER_PERIODIC = 1,
};
struct transfer_descriptor {
u32 addr; /* Buffer physical address */
u32 size:16; /* Buffer size in bytes */
u32 flags:16; /* Flag bitmask (see SPS_IOVEC_FLAG_ #defines) */
} __packed;
/* BAM pipe initialization parameters */
struct bam_pipe_parameters {
u16 event_threshold;
u32 pipe_irq_mask;
enum bam_pipe_dir dir;
enum bam_pipe_mode mode;
enum bam_write_nwd write_nwd;
phys_addr_t desc_base; /* Physical address of descriptor FIFO */
u32 desc_size; /* Size (bytes) of descriptor FIFO */
u32 lock_group; /* The lock group this pipe belongs to */
enum bam_stream_mode stream_mode;
u32 ee; /* BAM execution environment index */
/* The following are only valid if mode is BAM2BAM */
u32 peer_phys_addr;
u32 peer_pipe;
phys_addr_t data_base; /* Physical address of data FIFO */
u32 data_size; /* Size (bytes) of data FIFO */
};
/**
* Initialize a BAM device
*
* This function initializes a BAM device.
*
* @base - BAM virtual base address.
*
* @ee - BAM execution environment index
*
* @summing_threshold - summing threshold (global for all pipes)
*
* @irq_mask - error interrupts mask
*
* @version - return BAM hardware version
*
* @num_pipes - return number of pipes
*
* @options - BAM configuration options
*
* @return 0 on success, negative value on error
*
*/
int bam_init(void *base,
u32 ee,
u16 summing_threshold,
u32 irq_mask, u32 *version,
u32 *num_pipes, u32 options);
/**
* Initialize BAM device security execution environment
*
* @base - BAM virtual base address.
*
* @ee - BAM execution environment index
*
* @vmid - virtual master identifier
*
* @pipe_mask - bit mask of pipes to assign to EE
*
* @return 0 on success, negative value on error
*
*/
int bam_security_init(void *base, u32 ee, u32 vmid, u32 pipe_mask);
/**
* Check a BAM device
*
* This function verifies that a BAM device is enabled and gathers
* the hardware configuration.
*
* @base - BAM virtual base address.
*
* @version - return BAM hardware version
*
* @ee - BAM execution environment index
*
* @num_pipes - return number of pipes
*
* @return 0 on success, negative value on error
*
*/
int bam_check(void *base, u32 *version, u32 ee, u32 *num_pipes);
/**
* Disable a BAM device
*
* This function disables a BAM device.
*
* @base - BAM virtual base address.
*
* @ee - BAM execution environment index
*
*/
void bam_exit(void *base, u32 ee);
/**
* This function prints BAM register content
* including TEST_BUS and PIPE register content.
*
* @base - BAM virtual base address.
*
* @ee - BAM execution environment index
*/
void bam_output_register_content(void *base, u32 ee);
/**
* Get BAM IRQ source and clear global IRQ status
*
* This function gets BAM IRQ source.
* Clear global IRQ status if it is non-zero.
*
* @base - BAM virtual base address.
*
* @ee - BAM execution environment index
*
* @mask - active pipes mask.
*
* @case - callback case.
*
* @return IRQ status
*
*/
u32 bam_check_irq_source(void *base, u32 ee, u32 mask,
enum sps_callback_case *cb_case);
/**
* Initialize a BAM pipe
*
* This function initializes a BAM pipe.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @param - bam pipe parameters.
*
* @ee - BAM execution environment index
*
* @return 0 on success, negative value on error
*
*/
int bam_pipe_init(void *base, u32 pipe, struct bam_pipe_parameters *param,
u32 ee);
/**
* Reset the BAM pipe
*
* This function resets the BAM pipe.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @ee - BAM execution environment index
*
*/
void bam_pipe_exit(void *base, u32 pipe, u32 ee);
/**
* Enable a BAM pipe
*
* This function enables a BAM pipe.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
*/
void bam_pipe_enable(void *base, u32 pipe);
/**
* Disable a BAM pipe
*
* This function disables a BAM pipe.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
*/
void bam_pipe_disable(void *base, u32 pipe);
/**
* Get a BAM pipe enable state
*
* This function determines if a BAM pipe is enabled.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @return true if enabled, false if disabled
*
*/
int bam_pipe_is_enabled(void *base, u32 pipe);
/**
* Configure interrupt for a BAM pipe
*
* This function configures the interrupt for a BAM pipe.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @irq_en - enable or disable interrupt
*
* @src_mask - interrupt source mask, set regardless of whether
* interrupt is disabled
*
* @ee - BAM execution environment index
*
*/
void bam_pipe_set_irq(void *base, u32 pipe, enum bam_enable irq_en,
u32 src_mask, u32 ee);
/**
* Configure a BAM pipe for satellite MTI use
*
* This function configures a BAM pipe for satellite MTI use.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @irq_gen_addr - physical address written to generate MTI
*
* @ee - BAM execution environment index
*
*/
void bam_pipe_satellite_mti(void *base, u32 pipe, u32 irq_gen_addr, u32 ee);
/**
* Configure MTI for a BAM pipe
*
* This function configures the interrupt for a BAM pipe.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @irq_en - enable or disable interrupt
*
* @src_mask - interrupt source mask, set regardless of whether
* interrupt is disabled
*
* @irq_gen_addr - physical address written to generate MTI
*
*/
void bam_pipe_set_mti(void *base, u32 pipe, enum bam_enable irq_en,
u32 src_mask, u32 irq_gen_addr);
/**
* Get and Clear BAM pipe IRQ status
*
* This function gets and clears BAM pipe IRQ status.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @return IRQ status
*
*/
u32 bam_pipe_get_and_clear_irq_status(void *base, u32 pipe);
/**
* Set write offset for a BAM pipe
*
* This function sets the write offset for a BAM pipe. This is
* the offset that is maintained by software in system mode.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @next_write - descriptor FIFO write offset
*
*/
void bam_pipe_set_desc_write_offset(void *base, u32 pipe, u32 next_write);
/**
* Get write offset for a BAM pipe
*
* This function gets the write offset for a BAM pipe. This is
* the offset that is maintained by the pipe's peer pipe or by software.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @return descriptor FIFO write offset
*
*/
u32 bam_pipe_get_desc_write_offset(void *base, u32 pipe);
/**
* Get read offset for a BAM pipe
*
* This function gets the read offset for a BAM pipe. This is
* the offset that is maintained by the pipe in system mode.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @return descriptor FIFO read offset
*
*/
u32 bam_pipe_get_desc_read_offset(void *base, u32 pipe);
/**
* Configure inactivity timer count for a BAM pipe
*
* This function configures the inactivity timer count for a BAM pipe.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @mode - timer operating mode
*
* @timeout_count - timeout count
*
*/
void bam_pipe_timer_config(void *base, u32 pipe,
enum bam_pipe_timer_mode mode,
u32 timeout_count);
/**
* Reset inactivity timer for a BAM pipe
*
* This function resets the inactivity timer count for a BAM pipe.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
*/
void bam_pipe_timer_reset(void *base, u32 pipe);
/**
* Get inactivity timer count for a BAM pipe
*
* This function gets the inactivity timer count for a BAM pipe.
*
* @base - BAM virtual base address.
*
* @pipe - pipe index
*
* @return inactivity timer count
*
*/
u32 bam_pipe_timer_get_count(void *base, u32 pipe);
/*
* bam_pipe_check_zlt - Check if the last desc is ZLT.
* @base: BAM virtual address
* @pipe: pipe index
*
* This function checks if the last desc in the desc FIFO is a ZLT desc.
*
* @return true if the last desc in the desc FIFO is a ZLT desc. Otherwise
* return false.
*/
bool bam_pipe_check_zlt(void *base, u32 pipe);
/*
* bam_pipe_check_pipe_empty - Check if desc FIFO is empty.
* @base: BAM virtual address
* @pipe: pipe index
*
* This function checks if the desc FIFO of this pipe is empty.
*
* @return true if desc FIFO is empty. Otherwise return false.
*/
bool bam_pipe_check_pipe_empty(void *base, u32 pipe);
#endif /* _BAM_H_ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,608 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved.
*/
/*
* Function and data structure declarations for SPS BAM handling.
*/
#ifndef _SPSBAM_H_
#define _SPSBAM_H_
#include <linux/types.h>
#include <linux/completion.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include "spsi.h"
#define BAM_HANDLE_INVALID 0
#define to_sps_bam_dev(x) \
container_of((x), struct sps_bam, base)
enum bam_irq {
BAM_DEV_IRQ_RDY_TO_SLEEP = 0x00000001,
BAM_DEV_IRQ_HRESP_ERROR = 0x00000002,
BAM_DEV_IRQ_ERROR = 0x00000004,
BAM_DEV_IRQ_TIMER = 0x00000010,
};
/* Pipe interrupt mask */
enum bam_pipe_irq {
/* BAM finishes descriptor which has INT bit selected */
BAM_PIPE_IRQ_DESC_INT = 0x00000001,
/* Inactivity timer Expires */
BAM_PIPE_IRQ_TIMER = 0x00000002,
/* Wakeup peripheral (i.e. USB) */
BAM_PIPE_IRQ_WAKE = 0x00000004,
/* Producer - no free space for adding a descriptor */
/* Consumer - no descriptors for processing */
BAM_PIPE_IRQ_OUT_OF_DESC = 0x00000008,
/* Pipe Error interrupt */
BAM_PIPE_IRQ_ERROR = 0x00000010,
/* End-Of-Transfer */
BAM_PIPE_IRQ_EOT = 0x00000020,
/* Pipe RESET unsuccessful */
BAM_PIPE_IRQ_RST_ERROR = 0x00000040,
/* Errorneous Hresponse by AHB MASTER */
BAM_PIPE_IRQ_HRESP_ERROR = 0x00000080,
};
/* Halt Type */
enum bam_halt {
BAM_HALT_OFF = 0,
BAM_HALT_ON = 1,
};
/* Threshold values of the DMA channels */
enum bam_dma_thresh_dma {
BAM_DMA_THRESH_512 = 0x3,
BAM_DMA_THRESH_256 = 0x2,
BAM_DMA_THRESH_128 = 0x1,
BAM_DMA_THRESH_64 = 0x0,
};
/* Weight values of the DMA channels */
enum bam_dma_weight_dma {
BAM_DMA_WEIGHT_HIGH = 7,
BAM_DMA_WEIGHT_MED = 3,
BAM_DMA_WEIGHT_LOW = 1,
BAM_DMA_WEIGHT_DEFAULT = BAM_DMA_WEIGHT_LOW,
BAM_DMA_WEIGHT_DISABLE = 0,
};
/* Invalid pipe index value */
#define SPS_BAM_PIPE_INVALID ((u32)(-1))
/* Parameters for sps_bam_pipe_connect() */
struct sps_bam_connect_param {
/* which end point must be initialized */
enum sps_mode mode;
/* OR'd connection end point options (see SPS_O defines) */
u32 options;
/* SETPEND/MTI interrupt generation parameters */
u32 irq_gen_addr;
u32 irq_gen_data;
};
/* Event registration struct */
struct sps_bam_event_reg {
/* Client's event object handle */
struct completion *xfer_done;
void (*callback)(struct sps_event_notify *notify);
/* Event trigger mode */
enum sps_trigger mode;
/* User pointer that will be provided in event payload data */
void *user;
};
/* Descriptor FIFO cache entry */
struct sps_bam_desc_cache {
struct sps_iovec iovec;
void *user; /* User pointer registered with this transfer */
};
/* Forward declaration */
struct sps_bam;
/* System mode control */
struct sps_bam_sys_mode {
/* Descriptor FIFO control */
u8 *desc_buf; /* Descriptor FIFO for BAM pipe */
u32 desc_offset; /* Next new descriptor to be written to hardware */
u32 acked_offset; /* Next descriptor to be retired by software */
/* Descriptor cache control (!no_queue only) */
u8 *desc_cache; /* Software cache of descriptor FIFO contents */
u32 cache_offset; /* Next descriptor to be cached (ack_xfers only) */
/* User pointers associated with cached descriptors */
void **user_ptrs;
/* Event handling */
struct sps_bam_event_reg event_regs[SPS_EVENT_INDEX(SPS_EVENT_MAX)];
struct list_head events_q;
struct sps_q_event event; /* Temp storage for event creation */
int no_queue; /* Whether events are queued */
int ack_xfers; /* Whether client must ACK all descriptors */
int handler_eot; /* Whether EOT handling is in progress (debug) */
/* Statistics */
#ifdef SPS_BAM_STATISTICS
u32 desc_wr_count;
u32 desc_rd_count;
u32 user_ptrs_count;
u32 user_found;
u32 int_flags;
u32 eot_flags;
u32 callback_events;
u32 wait_events;
u32 queued_events;
u32 get_events;
u32 get_iovecs;
#endif /* SPS_BAM_STATISTICS */
};
/* BAM pipe descriptor */
struct sps_pipe {
struct list_head list;
/* Client state */
u32 client_state;
struct sps_bam *bam;
struct sps_connect connect;
const struct sps_connection *map;
/* Pipe parameters */
u32 state;
u32 pipe_index;
u32 pipe_index_mask;
u32 irq_mask;
int polled;
int hybrid;
bool late_eot;
u32 irq_gen_addr;
enum sps_mode mode;
u32 num_descs; /* Size (number of elements) of descriptor FIFO */
u32 desc_size; /* Size (bytes) of descriptor FIFO */
int wake_up_is_one_shot; /* Whether WAKEUP event is a one-shot or not */
/* System mode control */
struct sps_bam_sys_mode sys;
bool disconnecting;
};
/* BAM device descriptor */
struct sps_bam {
struct list_head list;
/* BAM device properties, including connection defaults */
struct sps_bam_props props;
/* BAM device state */
u32 state;
struct mutex lock;
void __iomem *base; /* BAM virtual base address */
u32 version;
spinlock_t isr_lock;
spinlock_t connection_lock;
unsigned long irqsave_flags;
/* Pipe state */
u32 pipe_active_mask;
u32 pipe_remote_mask;
struct sps_pipe *pipes[BAM_MAX_PIPES];
struct list_head pipes_q;
/* Statistics */
u32 irq_from_disabled_pipe;
u32 event_trigger_failures;
void *ipc_log0;
void *ipc_log1;
void *ipc_log2;
void *ipc_log3;
void *ipc_log4;
u32 ipc_loglevel;
/* Desc cache pointers */
u8 *desc_cache_pointers[BAM_MAX_PIPES];
};
/**
* BAM driver initialization
*
* This function initializes the BAM driver.
*
* @options - driver options bitflags (see SPS_OPT_*)
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_driver_init(u32 options);
/**
* BAM device initialization
*
* This function initializes a BAM device.
*
* @dev - pointer to BAM device descriptor
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_device_init(struct sps_bam *dev);
/**
* BAM device de-initialization
*
* This function de-initializes a BAM device.
*
* @dev - pointer to BAM device descriptor
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_device_de_init(struct sps_bam *dev);
/**
* BAM device reset
*
* This Function resets a BAM device.
*
* @dev - pointer to BAM device descriptor
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_reset(struct sps_bam *dev);
/**
* BAM device enable
*
* This function enables a BAM device.
*
* @dev - pointer to BAM device descriptor
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_enable(struct sps_bam *dev);
/**
* BAM device disable
*
* This Function disables a BAM device.
*
* @dev - pointer to BAM device descriptor
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_disable(struct sps_bam *dev);
/**
* Allocate a BAM pipe
*
* This function allocates a BAM pipe.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - client-specified pipe index, or SPS_BAM_PIPE_INVALID if
* any available pipe is acceptable
*
* @return - allocated pipe index, or SPS_BAM_PIPE_INVALID on error
*
*/
u32 sps_bam_pipe_alloc(struct sps_bam *dev, u32 pipe_index);
/**
* Free a BAM pipe
*
* This function frees a BAM pipe.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
*/
void sps_bam_pipe_free(struct sps_bam *dev, u32 pipe_index);
/**
* Establish BAM pipe connection
*
* This function establishes a connection for a BAM pipe (end point).
*
* @client - pointer to client pipe state struct
*
* @params - connection parameters
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_pipe_connect(struct sps_pipe *client,
const struct sps_bam_connect_param *params);
/**
* Disconnect a BAM pipe connection
*
* This function disconnects a connection for a BAM pipe (end point).
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_pipe_disconnect(struct sps_bam *dev, u32 pipe_index);
/**
* Set BAM pipe parameters
*
* This function sets parameters for a BAM pipe.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @options - bitflag options (see SPS_O_*)
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_pipe_set_params(struct sps_bam *dev, u32 pipe_index, u32 options);
/**
* Enable a BAM pipe
*
* This function enables a BAM pipe. Note that this function
* is separate from the pipe connect function to allow proper
* sequencing of consumer enable followed by producer enable.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_pipe_enable(struct sps_bam *dev, u32 pipe_index);
/**
* Disable a BAM pipe
*
* This function disables a BAM pipe.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_pipe_disable(struct sps_bam *dev, u32 pipe_index);
/**
* Register an event for a BAM pipe
*
* This function registers an event for a BAM pipe.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @reg - pointer to event registration struct
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_pipe_reg_event(struct sps_bam *dev, u32 pipe_index,
struct sps_register_event *reg);
/**
* Submit a transfer of a single buffer to a BAM pipe
*
* This function submits a transfer of a single buffer to a BAM pipe.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @addr - physical address of buffer to transfer
*
* @size - number of bytes to transfer
*
* @user - user pointer to register for event
*
* @flags - descriptor flags (see SPS_IOVEC_FLAG defines)
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_pipe_transfer_one(struct sps_bam *dev, u32 pipe_index, u32 addr,
u32 size, void *user, u32 flags);
/**
* Submit a transfer to a BAM pipe
*
* This function submits a transfer to a BAM pipe.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @transfer - pointer to transfer struct
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_pipe_transfer(struct sps_bam *dev, u32 pipe_index,
struct sps_transfer *transfer);
/**
* Get a BAM pipe event
*
* This function polls for a BAM pipe event.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @notify - pointer to event notification struct
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_pipe_get_event(struct sps_bam *dev, u32 pipe_index,
struct sps_event_notify *notify);
/**
* Get processed I/O vector
*
* This function fetches the next processed I/O vector.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @iovec - Pointer to I/O vector struct (output).
* This struct will be zeroed if there are no more processed I/O vectors.
*
* @return 0 on success, negative value on error
*/
int sps_bam_pipe_get_iovec(struct sps_bam *dev, u32 pipe_index,
struct sps_iovec *iovec);
/**
* Determine whether a BAM pipe descriptor FIFO is empty
*
* This function returns the empty state of a BAM pipe descriptor FIFO.
*
* The pipe mutex must be locked before calling this function.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @empty - pointer to client's empty status word (boolean)
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_pipe_is_empty(struct sps_bam *dev, u32 pipe_index, u32 *empty);
/**
* Get number of free slots in a BAM pipe descriptor FIFO
*
* This function returns the number of free slots in a BAM pipe descriptor FIFO.
*
* The pipe mutex must be locked before calling this function.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @count - pointer to count status
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_get_free_count(struct sps_bam *dev, u32 pipe_index, u32 *count);
/**
* Set BAM pipe to satellite ownership
*
* This function sets the BAM pipe to satellite ownership.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_set_satellite(struct sps_bam *dev, u32 pipe_index);
/**
* Perform BAM pipe timer control
*
* This function performs BAM pipe timer control operations.
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @timer_ctrl - Pointer to timer control specification
*
* @timer_result - Pointer to buffer for timer operation result.
* This argument can be NULL if no result is expected for the operation.
* If non-NULL, the current timer value will always provided.
*
* @return 0 on success, negative value on error
*
*/
int sps_bam_pipe_timer_ctrl(struct sps_bam *dev, u32 pipe_index,
struct sps_timer_ctrl *timer_ctrl,
struct sps_timer_result *timer_result);
/**
* Get the number of unused descriptors in the descriptor FIFO
* of a pipe
*
* @dev - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @desc_num - number of unused descriptors
*
*/
int sps_bam_pipe_get_unused_desc_num(struct sps_bam *dev, u32 pipe_index,
u32 *desc_num);
/*
* sps_bam_check_irq - check IRQ of a BAM device.
* @dev - pointer to BAM device descriptor
*
* This function checks any pending interrupt of a BAM device.
*
* Return: 0 on success, negative value on error
*/
int sps_bam_check_irq(struct sps_bam *dev);
/*
* sps_bam_pipe_pending_desc - checking pending descriptor.
* @dev: BAM device handle
* @pipe_index: pipe index
*
* This function checks if a pipe of a BAM has any pending descriptor.
*
* @return true if there is any desc pending
*/
bool sps_bam_pipe_pending_desc(struct sps_bam *dev, u32 pipe_index);
/*
* sps_bam_pipe_inject_zlt - inject a ZLT with EOT.
* @dev: BAM device handle
* @pipe_index: pipe index
*
* This function injects a ZLT with EOT for a pipe of a BAM.
*
* Return: 0 on success, negative value on error
*/
int sps_bam_pipe_inject_zlt(struct sps_bam *dev, u32 pipe_index);
#endif /* _SPSBAM_H_ */

View file

@ -0,0 +1,94 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011, 2013, 2015-2019, The Linux Foundation. All rights reserved.
*/
/*
* Function and data structure declarations.
*/
#ifndef _SPS_CORE_H_
#define _SPS_CORE_H_
#include <linux/types.h> /* u32 */
#include <linux/mutex.h> /* mutex */
#include <linux/list.h> /* list_head */
#include "spsi.h"
#include "sps_bam.h"
/* Connection state definitions */
#define SPS_STATE_DEF(x) ('S' | ('P' << 8) | ('S' << 16) | ((x) << 24))
#define IS_SPS_STATE_OK(x) \
(((x)->client_state & 0x00ffffff) == SPS_STATE_DEF(0))
/* Configuration indicating satellite connection */
#define SPS_CONFIG_SATELLITE 0x11111111
/* Client connection state */
#define SPS_STATE_DISCONNECT 0
#define SPS_STATE_ALLOCATE SPS_STATE_DEF(1)
#define SPS_STATE_CONNECT SPS_STATE_DEF(2)
#define SPS_STATE_ENABLE SPS_STATE_DEF(3)
#define SPS_STATE_DISABLE SPS_STATE_DEF(4)
/**
* Find the BAM device from the handle
*
* This function finds a BAM device in the BAM registration list that
* matches the specified device handle.
*
* @h - device handle of the BAM
*
* @return - pointer to the BAM device struct, or NULL on error
*
*/
struct sps_bam *sps_h2bam(unsigned long h);
/**
* Initialize resource manager module
*
* This function initializes the resource manager module.
*
* @rm - pointer to resource manager struct
*
* @options - driver options bitflags (see SPS_OPT_*)
*
* @return 0 on success, negative value on error
*
*/
int sps_rm_init(struct sps_rm *rm, u32 options);
/**
* De-initialize resource manager module
*
* This function de-initializes the resource manager module.
*
*/
void sps_rm_de_init(void);
/**
* Initialize client state context
*
* This function initializes a client state context struct.
*
* @connect - pointer to client connection state struct
*
*/
void sps_rm_config_init(struct sps_connect *connect);
/**
* Process connection state change
*
* This function processes a connection state change.
*
* @pipe - pointer to pipe context
*
* @state - new state for connection
*
* @return 0 on success, negative value on error
*
*/
int sps_rm_state_change(struct sps_pipe *pipe, u32 state);
#endif /* _SPS_CORE_H_ */

View file

@ -0,0 +1,919 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2013, 2015, 2017-2019, The Linux Foundation. All rights reserved.
*/
/* BAM-DMA Manager. */
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
#include <linux/export.h>
#include <linux/memory.h> /* memset */
#include "spsi.h"
#include "bam.h"
#include "sps_bam.h" /* bam_dma_thresh_dma */
#include "sps_core.h" /* sps_h2bam() */
/**
* registers
*/
#define DMA_ENBL (0x00000000)
#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
#define DMA_REVISION (0x00000004)
#define DMA_CONFIG (0x00000008)
#define DMA_CHNL_CONFIG(n) (0x00001000 + 4096 * (n))
#else
#define DMA_CHNL_CONFIG(n) (0x00000004 + 4 * (n))
#define DMA_CONFIG (0x00000040)
#endif
/**
* masks
*/
/* DMA_CHNL_confign */
#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
#define DMA_CHNL_PRODUCER_PIPE_ENABLED 0x40000
#define DMA_CHNL_CONSUMER_PIPE_ENABLED 0x20000
#endif
#define DMA_CHNL_HALT_DONE 0x10000
#define DMA_CHNL_HALT 0x1000
#define DMA_CHNL_ENABLE 0x100
#define DMA_CHNL_ACT_THRESH 0x30
#define DMA_CHNL_WEIGHT 0x7
/* DMA_CONFIG */
#define TESTBUS_SELECT 0x3
/**
*
* Write register with debug info.
*
* @base - bam base virtual address.
* @offset - register offset.
* @val - value to write.
*
*/
static inline void dma_write_reg(void *base, u32 offset, u32 val)
{
iowrite32(val, base + offset);
SPS_DBG(sps, "sps:bamdma: write reg 0x%x w_val 0x%x\n", offset, val);
}
/**
* Write register masked field with debug info.
*
* @base - bam base virtual address.
* @offset - register offset.
* @mask - register bitmask.
* @val - value to write.
*
*/
static inline void dma_write_reg_field(void *base, u32 offset,
const u32 mask, u32 val)
{
u32 shift = find_first_bit((void *)&mask, 32);
u32 tmp = ioread32(base + offset);
tmp &= ~mask; /* clear written bits */
val = tmp | (val << shift);
iowrite32(val, base + offset);
SPS_DBG(sps, "sps:bamdma: write reg 0x%x w_val 0x%x\n", offset, val);
}
/* Round max number of pipes to nearest multiple of 2 */
#define DMA_MAX_PIPES ((BAM_MAX_PIPES / 2) * 2)
/* Maximum number of BAM-DMAs supported */
#define MAX_BAM_DMA_DEVICES 1
/* Maximum number of BAMs that will be registered */
#define MAX_BAM_DMA_BAMS 1
/* Pipe enable check values */
#define DMA_PIPES_STATE_DIFF 0
#define DMA_PIPES_BOTH_DISABLED 1
#define DMA_PIPES_BOTH_ENABLED 2
/* Even pipe is tx/dest/input/write, odd pipe is rx/src/output/read */
#define DMA_PIPE_IS_DEST(p) (((p) & 1) == 0)
#define DMA_PIPE_IS_SRC(p) (((p) & 1) != 0)
/* BAM DMA pipe state */
enum bamdma_pipe_state {
PIPE_INACTIVE = 0,
PIPE_ACTIVE
};
/* BAM DMA channel state */
enum bamdma_chan_state {
DMA_CHAN_STATE_FREE = 0,
DMA_CHAN_STATE_ALLOC_EXT, /* Client allocation */
DMA_CHAN_STATE_ALLOC_INT /* Internal (resource mgr) allocation */
};
struct bamdma_chan {
/* Allocation state */
enum bamdma_chan_state state;
/* BAM DMA channel configuration parameters */
u32 threshold;
enum sps_dma_priority priority;
/* HWIO channel configuration parameters */
enum bam_dma_thresh_dma thresh;
enum bam_dma_weight_dma weight;
};
/* BAM DMA device state */
struct bamdma_device {
/* BAM-DMA device state */
int enabled;
int local;
/* BAM device state */
struct sps_bam *bam;
/* BAM handle, for deregistration */
unsigned long h;
/* BAM DMA device virtual mapping */
void *virt_addr;
int virtual_mapped;
phys_addr_t phys_addr;
void *hwio;
/* BAM DMA pipe/channel state */
u32 num_pipes;
enum bamdma_pipe_state pipes[DMA_MAX_PIPES];
struct bamdma_chan chans[DMA_MAX_PIPES / 2];
};
/* BAM-DMA devices */
static struct bamdma_device bam_dma_dev[MAX_BAM_DMA_DEVICES];
static struct mutex bam_dma_lock;
/*
* The BAM DMA module registers all BAMs in the BSP properties, but only
* uses the first BAM-DMA device for allocations. References to the others
* are stored in the following data array.
*/
static int num_bams;
static unsigned long bam_handles[MAX_BAM_DMA_BAMS];
/**
* Find BAM-DMA device
*
* This function finds the BAM-DMA device associated with the BAM handle.
*
* @h - BAM handle
*
* @return - pointer to BAM-DMA device, or NULL on error
*
*/
static struct bamdma_device *sps_dma_find_device(unsigned long h)
{
return &bam_dma_dev[0];
}
/**
* BAM DMA device enable
*
* This function enables a BAM DMA device and the associated BAM.
*
* @dev - pointer to BAM DMA device context
*
* @return 0 on success, negative value on error
*
*/
static int sps_dma_device_enable(struct bamdma_device *dev)
{
if (dev->enabled)
return 0;
/*
* If the BAM-DMA device is locally controlled then enable BAM-DMA
* device
*/
if (dev->local)
dma_write_reg(dev->virt_addr, DMA_ENBL, 1);
/* Enable BAM device */
if (sps_bam_enable(dev->bam)) {
SPS_ERR(sps, "sps:Failed to enable BAM DMA's BAM: %pa\n",
&dev->phys_addr);
return SPS_ERROR;
}
dev->enabled = true;
return 0;
}
/**
* BAM DMA device enable
*
* This function initializes a BAM DMA device.
*
* @dev - pointer to BAM DMA device context
*
* @return 0 on success, negative value on error
*
*/
static int sps_dma_device_disable(struct bamdma_device *dev)
{
u32 pipe_index;
if (!dev->enabled)
return 0;
/* Do not disable if channels active */
for (pipe_index = 0; pipe_index < dev->num_pipes; pipe_index++) {
if (dev->pipes[pipe_index] != PIPE_INACTIVE)
break;
}
if (pipe_index < dev->num_pipes) {
SPS_ERR(sps,
"sps:Fail to disable BAM-DMA %pa:channels are active\n",
&dev->phys_addr);
return SPS_ERROR;
}
dev->enabled = false;
/* Disable BAM device */
if (sps_bam_disable(dev->bam)) {
SPS_ERR(sps,
"sps:Fail to disable BAM-DMA BAM:%pa\n",
&dev->phys_addr);
return SPS_ERROR;
}
/* Is the BAM-DMA device locally controlled? */
if (dev->local)
/* Disable BAM-DMA device */
dma_write_reg(dev->virt_addr, DMA_ENBL, 0);
return 0;
}
/**
* Initialize BAM DMA device
*
*/
int sps_dma_device_init(unsigned long h)
{
struct bamdma_device *dev;
struct sps_bam_props *props;
int result = SPS_ERROR;
mutex_lock(&bam_dma_lock);
/* Find a free BAM-DMA device slot */
dev = NULL;
if (bam_dma_dev[0].bam != NULL) {
SPS_ERR(sps,
"sps:%s:BAM-DMA BAM device is already initialized\n",
__func__);
goto exit_err;
} else {
dev = &bam_dma_dev[0];
}
/* Record BAM */
memset(dev, 0, sizeof(*dev));
dev->h = h;
dev->bam = sps_h2bam(h);
if (dev->bam == NULL) {
SPS_ERR(sps,
"sps:%s:BAM-DMA BAM device is not found from the handle\n",
__func__);
goto exit_err;
}
/* Map the BAM DMA device into virtual space, if necessary */
props = &dev->bam->props;
dev->phys_addr = props->periph_phys_addr;
if (props->periph_virt_addr != NULL) {
dev->virt_addr = props->periph_virt_addr;
dev->virtual_mapped = false;
} else {
if (props->periph_virt_size == 0) {
SPS_ERR(sps,
"sps:Unable to map BAM DMA IO memory: %pa %x\n",
&dev->phys_addr, props->periph_virt_size);
goto exit_err;
}
dev->virt_addr = ioremap(dev->phys_addr,
props->periph_virt_size);
if (dev->virt_addr == NULL) {
SPS_ERR(sps,
"sps:Unable to map BAM DMA IO memory: %pa %x\n",
&dev->phys_addr, props->periph_virt_size);
goto exit_err;
}
dev->virtual_mapped = true;
}
dev->hwio = (void *) dev->virt_addr;
/* Is the BAM-DMA device locally controlled? */
if ((props->manage & SPS_BAM_MGR_DEVICE_REMOTE) == 0) {
SPS_DBG3(sps, "sps:BAM-DMA is controlled locally: %pa\n",
&dev->phys_addr);
dev->local = true;
} else {
SPS_DBG3(sps, "sps:BAM-DMA is controlled remotely: %pa\n",
&dev->phys_addr);
dev->local = false;
}
/*
* Enable the BAM DMA and determine the number of pipes/channels.
* Leave the BAM-DMA enabled, since it is always a shared device.
*/
if (sps_dma_device_enable(dev))
goto exit_err;
dev->num_pipes = dev->bam->props.num_pipes;
result = 0;
exit_err:
if (result) {
if (dev != NULL) {
if (dev->virtual_mapped)
iounmap(dev->virt_addr);
dev->bam = NULL;
}
}
mutex_unlock(&bam_dma_lock);
return result;
}
/**
* De-initialize BAM DMA device
*
*/
int sps_dma_device_de_init(unsigned long h)
{
struct bamdma_device *dev;
u32 pipe_index;
u32 chan;
int result = 0;
mutex_lock(&bam_dma_lock);
dev = sps_dma_find_device(h);
if (dev == NULL) {
SPS_ERR(sps, "sps:BAM-DMA: not registered: %pK\n", (void *)h);
result = SPS_ERROR;
goto exit_err;
}
/* Check for channel leaks */
for (chan = 0; chan < dev->num_pipes / 2; chan++) {
if (dev->chans[chan].state != DMA_CHAN_STATE_FREE) {
SPS_ERR(sps, "sps:BAM-DMA: channel not free: %d\n",
chan);
result = SPS_ERROR;
dev->chans[chan].state = DMA_CHAN_STATE_FREE;
}
}
for (pipe_index = 0; pipe_index < dev->num_pipes; pipe_index++) {
if (dev->pipes[pipe_index] != PIPE_INACTIVE) {
SPS_ERR(sps, "sps:BAM-DMA: pipe not inactive: %d\n",
pipe_index);
result = SPS_ERROR;
dev->pipes[pipe_index] = PIPE_INACTIVE;
}
}
/* Disable BAM and BAM-DMA */
if (sps_dma_device_disable(dev))
result = SPS_ERROR;
dev->h = BAM_HANDLE_INVALID;
dev->bam = NULL;
if (dev->virtual_mapped)
iounmap(dev->virt_addr);
exit_err:
mutex_unlock(&bam_dma_lock);
return result;
}
/**
* Initialize BAM DMA module
*
*/
int sps_dma_init(const struct sps_bam_props *bam_props)
{
struct sps_bam_props props;
const struct sps_bam_props *bam_reg;
unsigned long h;
/* Init local data */
memset(&bam_dma_dev, 0, sizeof(bam_dma_dev));
num_bams = 0;
memset(bam_handles, 0, sizeof(bam_handles));
/* Create a mutex to control access to the BAM-DMA devices */
mutex_init(&bam_dma_lock);
/* Are there any BAM DMA devices? */
if (bam_props == NULL)
return 0;
/*
* Registers all BAMs in the BSP properties, but only uses the first
* BAM-DMA device for allocations.
*/
if (bam_props->phys_addr) {
/* Force multi-EE option for all BAM-DMAs */
bam_reg = bam_props;
if ((bam_props->options & SPS_BAM_OPT_BAMDMA) &&
(bam_props->manage & SPS_BAM_MGR_MULTI_EE) == 0) {
SPS_DBG(sps,
"sps:Setting multi-EE options for BAM-DMA: %pa\n",
&bam_props->phys_addr);
props = *bam_props;
props.manage |= SPS_BAM_MGR_MULTI_EE;
bam_reg = &props;
}
/* Register the BAM */
if (sps_register_bam_device(bam_reg, &h)) {
SPS_ERR(sps,
"sps:Fail to register BAM-DMA BAM device: phys %pa\n",
&bam_props->phys_addr);
return SPS_ERROR;
}
/* Record the BAM so that it may be deregistered later */
if (num_bams < MAX_BAM_DMA_BAMS) {
bam_handles[num_bams] = h;
num_bams++;
} else {
SPS_ERR(sps, "sps:BAM-DMA: BAM limit exceeded: %d\n",
num_bams);
return SPS_ERROR;
}
} else {
SPS_ERR(sps,
"sps:%s:BAM-DMA phys_addr is zero\n",
__func__);
return SPS_ERROR;
}
return 0;
}
/**
* De-initialize BAM DMA module
*
*/
void sps_dma_de_init(void)
{
int n;
/* De-initialize the BAM devices */
for (n = 0; n < num_bams; n++)
sps_deregister_bam_device(bam_handles[n]);
/* Clear local data */
memset(&bam_dma_dev, 0, sizeof(bam_dma_dev));
num_bams = 0;
memset(bam_handles, 0, sizeof(bam_handles));
}
/**
* Allocate a BAM DMA channel
*
*/
int sps_alloc_dma_chan(const struct sps_alloc_dma_chan *alloc,
struct sps_dma_chan *chan_info)
{
struct bamdma_device *dev;
struct bamdma_chan *chan;
u32 pipe_index;
enum bam_dma_thresh_dma thresh = (enum bam_dma_thresh_dma) 0;
enum bam_dma_weight_dma weight = (enum bam_dma_weight_dma) 0;
int result = SPS_ERROR;
if (alloc == NULL || chan_info == NULL) {
SPS_ERR(sps,
"sps:%s:invalid parameters\n", __func__);
return SPS_ERROR;
}
/* Translate threshold and priority to hwio values */
if (alloc->threshold != SPS_DMA_THRESHOLD_DEFAULT) {
if (alloc->threshold >= 512)
thresh = BAM_DMA_THRESH_512;
else if (alloc->threshold >= 256)
thresh = BAM_DMA_THRESH_256;
else if (alloc->threshold >= 128)
thresh = BAM_DMA_THRESH_128;
else
thresh = BAM_DMA_THRESH_64;
}
weight = alloc->priority;
if ((u32)alloc->priority > (u32)BAM_DMA_WEIGHT_HIGH) {
SPS_ERR(sps, "sps:BAM-DMA: invalid priority: %x\n",
alloc->priority);
return SPS_ERROR;
}
mutex_lock(&bam_dma_lock);
dev = sps_dma_find_device(alloc->dev);
if (dev == NULL) {
SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %pK\n",
(void *)alloc->dev);
goto exit_err;
}
/* Search for a free set of pipes */
for (pipe_index = 0, chan = dev->chans;
pipe_index < dev->num_pipes; pipe_index += 2, chan++) {
if (chan->state == DMA_CHAN_STATE_FREE) {
/* Just check pipes for safety */
if (dev->pipes[pipe_index] != PIPE_INACTIVE ||
dev->pipes[pipe_index + 1] != PIPE_INACTIVE) {
SPS_ERR(sps,
"sps:BAM-DMA: channel %d state error:%d %d\n",
pipe_index / 2, dev->pipes[pipe_index],
dev->pipes[pipe_index + 1]);
goto exit_err;
}
break; /* Found free pipe */
}
}
if (pipe_index >= dev->num_pipes) {
SPS_ERR(sps, "sps:BAM-DMA: no free channel num_pipes = %d\n",
dev->num_pipes);
goto exit_err;
}
chan->state = DMA_CHAN_STATE_ALLOC_EXT;
/* Store config values for use when pipes are activated */
chan = &dev->chans[pipe_index / 2];
chan->threshold = alloc->threshold;
chan->thresh = thresh;
chan->priority = alloc->priority;
chan->weight = weight;
SPS_DBG3(sps, "sps:%s. pipe %d\n", __func__, pipe_index);
/* Report allocated pipes to client */
chan_info->dev = dev->h;
/* Dest/input/write pipex */
chan_info->dest_pipe_index = pipe_index;
/* Source/output/read pipe */
chan_info->src_pipe_index = pipe_index + 1;
result = 0;
exit_err:
mutex_unlock(&bam_dma_lock);
return result;
}
EXPORT_SYMBOL(sps_alloc_dma_chan);
/**
* Free a BAM DMA channel
*
*/
int sps_free_dma_chan(struct sps_dma_chan *chan)
{
struct bamdma_device *dev;
u32 pipe_index;
int result = 0;
if (chan == NULL) {
SPS_ERR(sps,
"sps:%s:chan is NULL\n", __func__);
return SPS_ERROR;
}
mutex_lock(&bam_dma_lock);
dev = sps_dma_find_device(chan->dev);
if (dev == NULL) {
SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %pK\n",
(void *)chan->dev);
result = SPS_ERROR;
goto exit_err;
}
/* Verify the pipe indices */
pipe_index = chan->dest_pipe_index;
if (pipe_index >= dev->num_pipes || ((pipe_index & 1)) ||
(pipe_index + 1) != chan->src_pipe_index) {
SPS_ERR(sps,
"sps:%s. Invalid pipe indices num_pipes=%d dest=%d src=%d\n",
__func__, dev->num_pipes,
chan->dest_pipe_index,
chan->src_pipe_index);
result = SPS_ERROR;
goto exit_err;
}
/* Are both pipes inactive? */
if (dev->chans[pipe_index / 2].state != DMA_CHAN_STATE_ALLOC_EXT ||
dev->pipes[pipe_index] != PIPE_INACTIVE ||
dev->pipes[pipe_index + 1] != PIPE_INACTIVE) {
SPS_ERR(sps,
"sps:BAM-DMA: attempt to free active chan %d: %d %d\n",
pipe_index / 2, dev->pipes[pipe_index],
dev->pipes[pipe_index + 1]);
result = SPS_ERROR;
goto exit_err;
}
/* Free the channel */
dev->chans[pipe_index / 2].state = DMA_CHAN_STATE_FREE;
exit_err:
mutex_unlock(&bam_dma_lock);
return result;
}
EXPORT_SYMBOL(sps_free_dma_chan);
/**
* Activate a BAM DMA pipe
*
* This function activates a BAM DMA pipe.
*
* @dev - pointer to BAM-DMA device descriptor
*
* @pipe_index - pipe index
*
* @return 0 on success, negative value on error
*
*/
static u32 sps_dma_check_pipes(struct bamdma_device *dev, u32 pipe_index)
{
u32 pipe_in;
u32 pipe_out;
int enabled_in;
int enabled_out;
u32 check;
pipe_in = pipe_index & ~1;
pipe_out = pipe_in + 1;
enabled_in = bam_pipe_is_enabled(&dev->bam->base, pipe_in);
enabled_out = bam_pipe_is_enabled(&dev->bam->base, pipe_out);
if (!enabled_in && !enabled_out)
check = DMA_PIPES_BOTH_DISABLED;
else if (enabled_in && enabled_out)
check = DMA_PIPES_BOTH_ENABLED;
else
check = DMA_PIPES_STATE_DIFF;
return check;
}
/**
* Allocate a BAM DMA pipe
*
*/
int sps_dma_pipe_alloc(void *bam_arg, u32 pipe_index, enum sps_mode dir)
{
struct sps_bam *bam = bam_arg;
struct bamdma_device *dev;
struct bamdma_chan *chan;
u32 channel;
int result = SPS_ERROR;
if (bam == NULL) {
SPS_ERR(sps, "%s\n", "sps:BAM context is NULL");
return SPS_ERROR;
}
/* Check pipe direction */
if ((DMA_PIPE_IS_DEST(pipe_index) && dir != SPS_MODE_DEST) ||
(DMA_PIPE_IS_SRC(pipe_index) && dir != SPS_MODE_SRC)) {
SPS_ERR(sps, "sps:BAM-DMA: wrong dir for BAM %pa pipe %d\n",
&bam->props.phys_addr, pipe_index);
return SPS_ERROR;
}
mutex_lock(&bam_dma_lock);
dev = sps_dma_find_device((unsigned long) bam);
if (dev == NULL) {
SPS_ERR(sps, "sps:BAM-DMA: invalid BAM: %pa\n",
&bam->props.phys_addr);
goto exit_err;
}
if (pipe_index >= dev->num_pipes) {
SPS_ERR(sps, "sps:BAM-DMA: BAM %pa invalid pipe: %d\n",
&bam->props.phys_addr, pipe_index);
goto exit_err;
}
if (dev->pipes[pipe_index] != PIPE_INACTIVE) {
SPS_ERR(sps, "sps:BAM-DMA: BAM %pa pipe %d already active\n",
&bam->props.phys_addr, pipe_index);
goto exit_err;
}
/* Mark pipe active */
dev->pipes[pipe_index] = PIPE_ACTIVE;
/* If channel is not allocated, make an internal allocation */
channel = pipe_index / 2;
chan = &dev->chans[channel];
if (chan->state != DMA_CHAN_STATE_ALLOC_EXT &&
chan->state != DMA_CHAN_STATE_ALLOC_INT) {
chan->state = DMA_CHAN_STATE_ALLOC_INT;
}
result = 0;
exit_err:
mutex_unlock(&bam_dma_lock);
return result;
}
/**
* Enable a BAM DMA pipe
*
*/
int sps_dma_pipe_enable(void *bam_arg, u32 pipe_index)
{
struct sps_bam *bam = bam_arg;
struct bamdma_device *dev;
struct bamdma_chan *chan;
u32 channel;
int result = SPS_ERROR;
SPS_DBG3(sps, "sps:%s pipe %d\n", __func__, pipe_index);
mutex_lock(&bam_dma_lock);
dev = sps_dma_find_device((unsigned long) bam);
if (dev == NULL) {
SPS_ERR(sps, "sps:%s:BAM-DMA: invalid BAM\n", __func__);
goto exit_err;
}
if (pipe_index >= dev->num_pipes) {
SPS_ERR(sps, "sps:BAM-DMA: BAM %pa invalid pipe: %d\n",
&bam->props.phys_addr, pipe_index);
goto exit_err;
}
if (dev->pipes[pipe_index] != PIPE_ACTIVE) {
SPS_ERR(sps, "sps:BAM-DMA: BAM %pa pipe %d not active\n",
&bam->props.phys_addr, pipe_index);
goto exit_err;
}
/*
* The channel must be enabled when the dest/input/write pipe
* is enabled
*/
if (DMA_PIPE_IS_DEST(pipe_index)) {
/* Configure and enable the channel */
channel = pipe_index / 2;
chan = &dev->chans[channel];
if (chan->threshold != SPS_DMA_THRESHOLD_DEFAULT)
dma_write_reg_field(dev->virt_addr,
DMA_CHNL_CONFIG(channel),
DMA_CHNL_ACT_THRESH,
chan->thresh);
if (chan->priority != SPS_DMA_PRI_DEFAULT)
dma_write_reg_field(dev->virt_addr,
DMA_CHNL_CONFIG(channel),
DMA_CHNL_WEIGHT,
chan->weight);
dma_write_reg_field(dev->virt_addr,
DMA_CHNL_CONFIG(channel),
DMA_CHNL_ENABLE, 1);
}
result = 0;
exit_err:
mutex_unlock(&bam_dma_lock);
return result;
}
/**
* Deactivate a BAM DMA pipe
*
* This function deactivates a BAM DMA pipe.
*
* @dev - pointer to BAM-DMA device descriptor
*
* @bam - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @return 0 on success, negative value on error
*
*/
static int sps_dma_deactivate_pipe_atomic(struct bamdma_device *dev,
struct sps_bam *bam,
u32 pipe_index)
{
u32 channel;
if (dev->bam != bam)
return SPS_ERROR;
if (pipe_index >= dev->num_pipes)
return SPS_ERROR;
if (dev->pipes[pipe_index] != PIPE_ACTIVE)
return SPS_ERROR; /* Pipe is not active */
SPS_DBG3(sps, "sps:BAM-DMA: deactivate pipe %d\n", pipe_index);
/* Mark pipe inactive */
dev->pipes[pipe_index] = PIPE_INACTIVE;
/*
* Channel must be reset when either pipe is disabled, so just always
* reset regardless of other pipe's state
*/
channel = pipe_index / 2;
dma_write_reg_field(dev->virt_addr, DMA_CHNL_CONFIG(channel),
DMA_CHNL_ENABLE, 0);
/* If the peer pipe is also inactive, reset the channel */
if (sps_dma_check_pipes(dev, pipe_index) == DMA_PIPES_BOTH_DISABLED) {
/* Free channel if allocated internally */
if (dev->chans[channel].state == DMA_CHAN_STATE_ALLOC_INT)
dev->chans[channel].state = DMA_CHAN_STATE_FREE;
}
return 0;
}
/**
* Free a BAM DMA pipe
*
*/
int sps_dma_pipe_free(void *bam_arg, u32 pipe_index)
{
struct bamdma_device *dev;
struct sps_bam *bam = bam_arg;
int result;
mutex_lock(&bam_dma_lock);
dev = sps_dma_find_device((unsigned long) bam);
if (dev == NULL) {
SPS_ERR(sps, "sps:%s:BAM-DMA: invalid BAM\n", __func__);
result = SPS_ERROR;
goto exit_err;
}
result = sps_dma_deactivate_pipe_atomic(dev, bam, pipe_index);
exit_err:
mutex_unlock(&bam_dma_lock);
return result;
}
/**
* Get the BAM handle for BAM-DMA.
*
* The BAM handle should be use as source/destination in the sps_connect().
*
* @return bam handle on success, zero on error
*/
unsigned long sps_dma_get_bam_handle(void)
{
return (unsigned long)bam_dma_dev[0].bam;
}
EXPORT_SYMBOL(sps_dma_get_bam_handle);
/**
* Free the BAM handle for BAM-DMA.
*
*/
void sps_dma_free_bam_handle(unsigned long h)
{
}
EXPORT_SYMBOL(sps_dma_free_bam_handle);
#endif /* CONFIG_SPS_SUPPORT_BAMDMA */

View file

@ -0,0 +1,131 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2013, 2015, 2017-2019, The Linux Foundation. All rights reserved.
*/
/**
* Connection mapping table management for SPS device driver.
*/
#include <linux/types.h> /* u32 */
#include <linux/kernel.h> /* pr_info() */
#include <linux/memory.h> /* memset */
#include "spsi.h"
/* Module state */
struct sps_map_state {
const struct sps_map *maps;
u32 num_maps;
u32 options;
};
static struct sps_map_state sps_maps;
/**
* Initialize connection mapping module
*
*/
int sps_map_init(const struct sps_map *map_props, u32 options)
{
const struct sps_map *maps;
/* Are there any connection mappings? */
memset(&sps_maps, 0, sizeof(sps_maps));
if (map_props == NULL)
return 0;
/* Init the module state */
sps_maps.maps = map_props;
sps_maps.options = options;
for (maps = sps_maps.maps;; maps++, sps_maps.num_maps++)
if (maps->src.periph_class == SPS_CLASS_INVALID &&
maps->src.periph_phy_addr == SPS_ADDR_INVALID)
break;
SPS_DBG(sps, "sps: %d mappings\n", sps_maps.num_maps);
return 0;
}
/**
* De-initialize connection mapping module
*
*/
void sps_map_de_init(void)
{
memset(&sps_maps, 0, sizeof(sps_maps));
}
/**
* Find matching connection mapping
*
*/
int sps_map_find(struct sps_connect *connect)
{
const struct sps_map *map;
u32 i;
void *desc;
void *data;
/* Are there any connection mappings? */
if (sps_maps.num_maps == 0)
return SPS_ERROR;
/* Search the mapping table for a match to the specified connection */
for (i = sps_maps.num_maps, map = sps_maps.maps;
i > 0; i--, map++)
if (map->src.periph_class == (u32) connect->source &&
map->dest.periph_class == (u32) connect->destination
&& map->config == (u32) connect->config)
break;
if (i == 0)
return SPS_ERROR;
/*
* Before modifying client parameter struct, perform all
* operations that might fail
*/
desc = spsi_get_mem_ptr(map->desc_base);
if (desc == NULL) {
SPS_ERR(sps,
"sps:Cannot get virt addr for I/O buffer: %pa\n",
&map->desc_base);
return SPS_ERROR;
}
if (map->data_size > 0 && map->data_base != SPS_ADDR_INVALID) {
data = spsi_get_mem_ptr(map->data_base);
if (data == NULL) {
SPS_ERR(sps,
"sps:Can't get virt addr for I/O buffer: %pa\n",
&map->data_base);
return SPS_ERROR;
}
} else {
data = NULL;
}
/* Copy mapping values to client parameter struct */
if (connect->source != SPS_DEV_HANDLE_MEM)
connect->src_pipe_index = map->src.pipe_index;
if (connect->destination != SPS_DEV_HANDLE_MEM)
connect->dest_pipe_index = map->dest.pipe_index;
if (connect->mode == SPS_MODE_SRC)
connect->event_thresh = map->src.event_thresh;
else
connect->event_thresh = map->dest.event_thresh;
connect->desc.size = map->desc_size;
connect->desc.phys_base = map->desc_base;
connect->desc.base = desc;
if (map->data_size > 0 && map->data_base != SPS_ADDR_INVALID) {
connect->data.size = map->data_size;
connect->data.phys_base = map->data_base;
connect->data.base = data;
}
return 0;
}

View file

@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011, 2013, 2016-2019, The Linux Foundation. All rights reserved.
*/
/* SPS driver mapping table data declarations. */
#ifndef _SPS_MAP_H_
#define _SPS_MAP_H_
#include <linux/types.h> /* u32 */
/* End point parameters */
struct sps_map_end_point {
u32 periph_class; /* Peripheral device enumeration class */
phys_addr_t periph_phy_addr; /* Peripheral base address */
u32 pipe_index; /* Pipe index */
u32 event_thresh; /* Pipe event threshold */
};
/* Mapping connection descriptor */
struct sps_map {
/* Source end point parameters */
struct sps_map_end_point src;
/* Destination end point parameters */
struct sps_map_end_point dest;
/* Resource parameters */
u32 config; /* Configuration (stream) identifier */
phys_addr_t desc_base; /* Physical address of descriptor FIFO */
u32 desc_size; /* Size (bytes) of descriptor FIFO */
phys_addr_t data_base; /* Physical address of data FIFO */
u32 data_size; /* Size (bytes) of data FIFO */
};
#endif /* _SPS_MAP_H_ */

View file

@ -0,0 +1,163 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011, 2013, 2015, 2017-2019, The Linux Foundation. All rights reserved.
*/
/**
* Pipe-Memory allocation/free management.
*/
#include <linux/types.h> /* u32 */
#include <linux/kernel.h> /* pr_info() */
#include <linux/io.h> /* ioremap() */
#include <linux/mutex.h> /* mutex */
#include <linux/list.h> /* list_head */
#include <linux/genalloc.h> /* gen_pool_alloc() */
#include <linux/errno.h> /* ENOMEM */
#include "sps_bam.h"
#include "spsi.h"
static phys_addr_t iomem_phys;
static void *iomem_virt;
static u32 iomem_size;
static u32 iomem_offset;
static struct gen_pool *pool;
static u32 nid = 0xaa;
/* Debug */
static u32 total_alloc;
static u32 total_free;
/**
* Translate physical to virtual address
*
*/
void *spsi_get_mem_ptr(phys_addr_t phys_addr)
{
void *virt = NULL;
if ((phys_addr >= iomem_phys) &&
(phys_addr < (iomem_phys + iomem_size))) {
virt = (u8 *) iomem_virt + (phys_addr - iomem_phys);
} else {
virt = phys_to_virt(phys_addr);
SPS_ERR(sps, "sps:%s.invalid phys addr=0x%pa\n",
__func__, &phys_addr);
}
return virt;
}
/**
* Allocate I/O (pipe) memory
*
*/
phys_addr_t sps_mem_alloc_io(u32 bytes)
{
phys_addr_t phys_addr = SPS_ADDR_INVALID;
unsigned long virt_addr = 0;
virt_addr = gen_pool_alloc(pool, bytes);
if (virt_addr) {
iomem_offset = virt_addr - (uintptr_t) iomem_virt;
phys_addr = iomem_phys + iomem_offset;
total_alloc += bytes;
} else {
SPS_ERR(sps, "sps:gen_pool_alloc %d bytes fail\n", bytes);
return SPS_ADDR_INVALID;
}
SPS_DBG3(sps, "sps:%s.phys=%pa.virt=0x%pK.size=0x%x\n",
__func__, &phys_addr, (void *)virt_addr, bytes);
return phys_addr;
}
/**
* Free I/O memory
*
*/
void sps_mem_free_io(phys_addr_t phys_addr, u32 bytes)
{
unsigned long virt_addr = 0;
iomem_offset = phys_addr - iomem_phys;
virt_addr = (uintptr_t) iomem_virt + iomem_offset;
SPS_DBG3(sps, "sps:%s.phys=%pa.virt=0x%pK.size=0x%x\n",
__func__, &phys_addr, (void *)virt_addr, bytes);
gen_pool_free(pool, virt_addr, bytes);
total_free += bytes;
}
/**
* Initialize driver memory module
*
*/
int sps_mem_init(phys_addr_t pipemem_phys_base, u32 pipemem_size)
{
int res;
/* 2^8=128. The desc-fifo and data-fifo minimal allocation. */
int min_alloc_order = 8;
if ((d_type == 0) || (d_type == 2) || imem) {
iomem_phys = pipemem_phys_base;
iomem_size = pipemem_size;
if (iomem_phys == 0) {
SPS_ERR(sps, "sps:%s:Invalid Pipe-Mem address\n",
__func__);
return SPS_ERROR;
}
iomem_virt = ioremap(iomem_phys, iomem_size);
if (!iomem_virt) {
SPS_ERR(sps,
"sps:%s:Failed to IO map pipe memory\n",
__func__);
return -ENOMEM;
}
iomem_offset = 0;
SPS_DBG(sps,
"sps:%s.iomem_phys=%pa,iomem_virt=0x%pK\n",
__func__, &iomem_phys, iomem_virt);
}
pool = gen_pool_create(min_alloc_order, nid);
if (!pool) {
SPS_ERR(sps, "sps:%s:Failed to create a new memory pool\n",
__func__);
return -ENOMEM;
}
if ((d_type == 0) || (d_type == 2) || imem) {
res = gen_pool_add(pool, (uintptr_t)iomem_virt,
iomem_size, nid);
if (res)
return res;
}
return 0;
}
/**
* De-initialize driver memory module
*
*/
int sps_mem_de_init(void)
{
if (iomem_virt != NULL) {
gen_pool_destroy(pool);
pool = NULL;
iounmap(iomem_virt);
iomem_virt = NULL;
}
if (total_alloc == total_free)
return 0;
SPS_ERR(sps, "sps:%s:some memory not free\n", __func__);
return SPS_ERROR;
}

View file

@ -0,0 +1,864 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2015, 2017-2019, The Linux Foundation. All rights reserved.
*/
/* Resource management for the SPS device driver. */
#include <linux/types.h> /* u32 */
#include <linux/kernel.h> /* pr_info() */
#include <linux/mutex.h> /* mutex */
#include <linux/list.h> /* list_head */
#include <linux/slab.h> /* kzalloc() */
#include <linux/memory.h> /* memset */
#include <linux/interrupt.h>
#include "spsi.h"
#include "sps_core.h"
/* Max BAM FIFO sizes */
#define SPSRM_MAX_DESC_FIFO_SIZE 0xffff
#define SPSRM_MAX_DATA_FIFO_SIZE 0xffff
/* Connection control struct pointer */
static struct sps_rm *sps_rm;
/**
* Initialize resource manager module
*/
int sps_rm_init(struct sps_rm *rm, u32 options)
{
/* Set the resource manager state struct pointer */
sps_rm = rm;
/* Initialize the state struct */
INIT_LIST_HEAD(&sps_rm->connections_q);
mutex_init(&sps_rm->lock);
return 0;
}
/**
* Initialize client state context
*
*/
void sps_rm_config_init(struct sps_connect *connect)
{
memset(connect, SPSRM_CLEAR, sizeof(*connect));
}
/**
* Remove reference to connection mapping
*
* This function removes a reference from a connection mapping struct.
*
* @map - pointer to connection mapping struct
*
*/
static void sps_rm_remove_ref(struct sps_connection *map)
{
/* Free this connection */
map->refs--;
if (map->refs <= 0) {
if (map->client_src != NULL || map->client_dest != NULL)
SPS_ERR(sps,
"sps:%s:Failed to allocate connection struct\n",
__func__);
list_del(&map->list);
kfree(map);
}
}
/**
* Compare map to connect parameters
*
* This function compares client connect parameters to an allocated
* connection mapping.
*
* @pipe - client context for SPS connection end point
*
* @return - true if match, false otherwise
*
*/
static int sps_rm_map_match(const struct sps_connect *cfg,
const struct sps_connection *map)
{
if (cfg->source != map->src.dev ||
cfg->destination != map->dest.dev)
return false;
if (cfg->src_pipe_index != SPSRM_CLEAR &&
cfg->src_pipe_index != map->src.pipe_index)
return false;
if (cfg->dest_pipe_index != SPSRM_CLEAR &&
cfg->dest_pipe_index != map->dest.pipe_index)
return false;
if (cfg->config != map->config)
return false;
if (cfg->desc.size != SPSRM_CLEAR) {
if (cfg->desc.size != map->desc.size)
return false;
if (cfg->desc.phys_base != (SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
cfg->desc.base != (void *)(SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
(cfg->desc.phys_base != map->desc.phys_base ||
cfg->desc.base != map->desc.base)) {
return false;
}
}
if (cfg->data.size != SPSRM_CLEAR) {
if (cfg->data.size != map->data.size)
return false;
if (cfg->data.phys_base != (SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
cfg->data.base != (void *)(SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
(cfg->data.phys_base != map->data.phys_base ||
cfg->data.base != map->data.base))
return false;
}
return true;
}
/**
* Find unconnected mapping
*
* This function finds an allocated a connection mapping.
*
* @pipe - client context for SPS connection end point
*
* @return - pointer to allocated connection mapping, or NULL if not found
*
*/
static struct sps_connection *find_unconnected(struct sps_pipe *pipe)
{
struct sps_connect *cfg = &pipe->connect;
struct sps_connection *map;
/* Has this connection already been allocated? */
list_for_each_entry(map, &sps_rm->connections_q, list) {
if (sps_rm_map_match(cfg, map))
if ((cfg->mode == SPS_MODE_SRC
&& map->client_src == NULL)
|| (cfg->mode != SPS_MODE_SRC
&& map->client_dest == NULL))
return map; /* Found */
}
return NULL; /* Not Found */
}
/**
* Assign connection to client
*
* This function assigns a connection to a client.
*
* @pipe - client context for SPS connection end point
*
* @map - connection mapping
*
* @return 0 on success, negative value on error
*
*/
static int sps_rm_assign(struct sps_pipe *pipe,
struct sps_connection *map)
{
struct sps_connect *cfg = &pipe->connect;
unsigned long desc_iova = 0;
unsigned long data_iova = 0;
/* Check ownership and BAM */
if ((cfg->mode == SPS_MODE_SRC && map->client_src != NULL) ||
(cfg->mode != SPS_MODE_SRC && map->client_dest != NULL)) {
SPS_ERR(sps,
"sps:%s:The end point is already connected\n",
__func__);
return SPS_ERROR;
}
/* Check whether this end point is a BAM (not memory) */
if ((cfg->mode == SPS_MODE_SRC && map->src.bam == NULL) ||
(cfg->mode != SPS_MODE_SRC && map->dest.bam == NULL)) {
SPS_ERR(sps, "sps:%s:The end point is empty\n", __func__);
return SPS_ERROR;
}
/* Record the connection assignment */
if (cfg->mode == SPS_MODE_SRC) {
map->client_src = pipe;
pipe->bam = map->src.bam;
pipe->pipe_index = map->src.pipe_index;
if (pipe->connect.event_thresh != SPSRM_CLEAR)
map->src.event_threshold = pipe->connect.event_thresh;
if (pipe->connect.lock_group != SPSRM_CLEAR)
map->src.lock_group = pipe->connect.lock_group;
} else {
map->client_dest = pipe;
pipe->bam = map->dest.bam;
pipe->pipe_index = map->dest.pipe_index;
if (pipe->connect.event_thresh != SPSRM_CLEAR)
map->dest.event_threshold =
pipe->connect.event_thresh;
if (pipe->connect.lock_group != SPSRM_CLEAR)
map->dest.lock_group = pipe->connect.lock_group;
}
pipe->map = map;
SPS_DBG(pipe->bam, "sps:%s.bam %pa.pipe_index=%d\n",
__func__, BAM_ID(pipe->bam), pipe->pipe_index);
/* Copy parameters to client connect state */
pipe->connect.src_pipe_index = map->src.pipe_index;
pipe->connect.dest_pipe_index = map->dest.pipe_index;
/*
* The below assignment to connect.desc and connect.data will
* overwrite the previous values given by the first client
* in a BAM-to-BAM connection. Prevent that since the IOVAs
* may be different for the same physical buffers if the
* BAMs use different SMMUs.
*/
if (pipe->bam->props.options & SPS_BAM_SMMU_EN) {
desc_iova = pipe->connect.desc.iova;
data_iova = pipe->connect.data.iova;
}
pipe->connect.desc = map->desc;
pipe->connect.data = map->data;
if (pipe->bam->props.options & SPS_BAM_SMMU_EN) {
pipe->connect.desc.iova = desc_iova;
pipe->connect.data.iova = data_iova;
}
pipe->client_state = SPS_STATE_ALLOCATE;
return 0;
}
/**
* Free connection mapping resources
*
* This function frees a connection mapping resources.
*
* @pipe - client context for SPS connection end point
*
*/
static void sps_rm_free_map_rsrc(struct sps_connection *map)
{
struct sps_bam *bam;
if (map->client_src != NULL || map->client_dest != NULL)
return;
if (map->alloc_src_pipe != SPS_BAM_PIPE_INVALID) {
bam = map->src.bam;
sps_bam_pipe_free(bam, map->src.pipe_index);
/* Is this a BAM-DMA pipe? */
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
if ((bam->props.options & SPS_BAM_OPT_BAMDMA))
/* Deallocate and free the BAM-DMA channel */
sps_dma_pipe_free(bam, map->src.pipe_index);
#endif
map->alloc_src_pipe = SPS_BAM_PIPE_INVALID;
map->src.pipe_index = SPS_BAM_PIPE_INVALID;
}
if (map->alloc_dest_pipe != SPS_BAM_PIPE_INVALID) {
bam = map->dest.bam;
sps_bam_pipe_free(bam, map->dest.pipe_index);
/* Is this a BAM-DMA pipe? */
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
if ((bam->props.options & SPS_BAM_OPT_BAMDMA)) {
/* Deallocate the BAM-DMA channel */
sps_dma_pipe_free(bam, map->dest.pipe_index);
}
#endif
map->alloc_dest_pipe = SPS_BAM_PIPE_INVALID;
map->dest.pipe_index = SPS_BAM_PIPE_INVALID;
}
if (map->alloc_desc_base != SPS_ADDR_INVALID) {
sps_mem_free_io(map->alloc_desc_base, map->desc.size);
map->alloc_desc_base = SPS_ADDR_INVALID;
map->desc.phys_base = SPS_ADDR_INVALID;
}
if (map->alloc_data_base != SPS_ADDR_INVALID) {
sps_mem_free_io(map->alloc_data_base, map->data.size);
map->alloc_data_base = SPS_ADDR_INVALID;
map->data.phys_base = SPS_ADDR_INVALID;
}
}
/**
* Init connection mapping from client connect
*
* This function initializes a connection mapping from the client's
* connect parameters.
*
* @map - connection mapping struct
*
* @cfg - client connect parameters
*
* @return - pointer to allocated connection mapping, or NULL on error
*
*/
static void sps_rm_init_map(struct sps_connection *map,
const struct sps_connect *cfg)
{
/* Clear the connection mapping struct */
memset(map, 0, sizeof(*map));
map->desc.phys_base = SPS_ADDR_INVALID;
map->data.phys_base = SPS_ADDR_INVALID;
map->alloc_desc_base = SPS_ADDR_INVALID;
map->alloc_data_base = SPS_ADDR_INVALID;
map->alloc_src_pipe = SPS_BAM_PIPE_INVALID;
map->alloc_dest_pipe = SPS_BAM_PIPE_INVALID;
/* Copy client required parameters */
map->src.dev = cfg->source;
map->dest.dev = cfg->destination;
map->desc.size = cfg->desc.size;
map->data.size = cfg->data.size;
map->config = cfg->config;
/* Did client specify descriptor FIFO? */
if (map->desc.size != SPSRM_CLEAR &&
cfg->desc.phys_base != (SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
cfg->desc.base != (void *)(SPSRM_CLEAR|SPSRM_ADDR_CLR))
map->desc = cfg->desc;
/* Did client specify data FIFO? */
if (map->data.size != SPSRM_CLEAR &&
cfg->data.phys_base != (SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
cfg->data.base != (void *)(SPSRM_CLEAR|SPSRM_ADDR_CLR))
map->data = cfg->data;
/* Did client specify source pipe? */
if (cfg->src_pipe_index != SPSRM_CLEAR)
map->src.pipe_index = cfg->src_pipe_index;
else
map->src.pipe_index = SPS_BAM_PIPE_INVALID;
/* Did client specify destination pipe? */
if (cfg->dest_pipe_index != SPSRM_CLEAR)
map->dest.pipe_index = cfg->dest_pipe_index;
else
map->dest.pipe_index = SPS_BAM_PIPE_INVALID;
}
/**
* Create a new connection mapping
*
* This function creates a new connection mapping.
*
* @pipe - client context for SPS connection end point
*
* @return - pointer to allocated connection mapping, or NULL on error
*
*/
static struct sps_connection *sps_rm_create(struct sps_pipe *pipe)
{
struct sps_connection *map;
struct sps_bam *bam;
u32 desc_size;
u32 data_size;
enum sps_mode dir;
int success = false;
/* Allocate new connection */
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (map == NULL) {
SPS_ERR(sps,
"sps:%s:Failed to allocate connection struct\n",
__func__);
return NULL;
}
/* Initialize connection struct */
sps_rm_init_map(map, &pipe->connect);
dir = pipe->connect.mode;
/* Use a do/while() loop to avoid a "goto" */
success = false;
/* Get BAMs */
map->src.bam = sps_h2bam(map->src.dev);
if (map->src.bam == NULL) {
if (map->src.dev != SPS_DEV_HANDLE_MEM) {
SPS_ERR(sps, "sps:Invalid BAM handle: %pK\n",
(void *)(&map->src.dev));
goto exit_err;
}
map->src.pipe_index = SPS_BAM_PIPE_INVALID;
}
map->dest.bam = sps_h2bam(map->dest.dev);
if (map->dest.bam == NULL) {
if (map->dest.dev != SPS_DEV_HANDLE_MEM) {
SPS_ERR(sps, "sps:Invalid BAM handle: %pK\n",
(void *)(&map->dest.dev));
goto exit_err;
}
map->dest.pipe_index = SPS_BAM_PIPE_INVALID;
}
/* Check the BAM device for the pipe */
if ((dir == SPS_MODE_SRC && map->src.bam == NULL) ||
(dir != SPS_MODE_SRC && map->dest.bam == NULL)) {
SPS_ERR(sps, "sps:Invalid BAM endpt: dir %d src %pK dest %pK\n",
dir, (void *)(&map->src.dev), (void *)(&map->dest.dev));
goto exit_err;
}
/* Allocate pipes and copy BAM parameters */
if (map->src.bam != NULL) {
/* Allocate the pipe */
bam = map->src.bam;
map->alloc_src_pipe = sps_bam_pipe_alloc(bam,
map->src.pipe_index);
if (map->alloc_src_pipe == SPS_BAM_PIPE_INVALID)
goto exit_err;
map->src.pipe_index = map->alloc_src_pipe;
/* Is this a BAM-DMA pipe? */
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
if ((bam->props.options & SPS_BAM_OPT_BAMDMA)) {
int rc;
/* Allocate the BAM-DMA channel */
rc = sps_dma_pipe_alloc(bam, map->src.pipe_index,
SPS_MODE_SRC);
if (rc) {
SPS_ERR(bam,
"sps:Failed to alloc BAM-DMA pipe: %d\n",
map->src.pipe_index);
goto exit_err;
}
}
#endif
map->src.bam_phys = bam->props.phys_addr;
map->src.event_threshold = bam->props.event_threshold;
}
if (map->dest.bam != NULL) {
/* Allocate the pipe */
bam = map->dest.bam;
map->alloc_dest_pipe = sps_bam_pipe_alloc(bam,
map->dest.pipe_index);
if (map->alloc_dest_pipe == SPS_BAM_PIPE_INVALID)
goto exit_err;
map->dest.pipe_index = map->alloc_dest_pipe;
/* Is this a BAM-DMA pipe? */
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
if ((bam->props.options & SPS_BAM_OPT_BAMDMA)) {
int rc;
/* Allocate the BAM-DMA channel */
rc = sps_dma_pipe_alloc(bam, map->dest.pipe_index,
SPS_MODE_DEST);
if (rc) {
SPS_ERR(bam,
"sps:Failed to alloc BAM-DMA pipe: %d\n",
map->dest.pipe_index);
goto exit_err;
}
}
#endif
map->dest.bam_phys = bam->props.phys_addr;
map->dest.event_threshold =
bam->props.event_threshold;
}
/* Get default FIFO sizes */
desc_size = 0;
data_size = 0;
if (map->src.bam != NULL) {
bam = map->src.bam;
desc_size = bam->props.desc_size;
data_size = bam->props.data_size;
}
if (map->dest.bam != NULL) {
bam = map->dest.bam;
if (bam->props.desc_size > desc_size)
desc_size = bam->props.desc_size;
if (bam->props.data_size > data_size)
data_size = bam->props.data_size;
}
/* Set FIFO sizes */
if (map->desc.size == SPSRM_CLEAR)
map->desc.size = desc_size;
if (map->src.bam != NULL && map->dest.bam != NULL) {
/* BAM-to-BAM requires data FIFO */
if (map->data.size == SPSRM_CLEAR)
map->data.size = data_size;
} else {
map->data.size = 0;
}
if (map->desc.size > SPSRM_MAX_DESC_FIFO_SIZE) {
SPS_ERR(sps, "sps:Invalid desc FIFO size: 0x%x\n",
map->desc.size);
goto exit_err;
}
if (map->src.bam != NULL && map->dest.bam != NULL &&
map->data.size > SPSRM_MAX_DATA_FIFO_SIZE) {
SPS_ERR(sps, "sps:Invalid data FIFO size: 0x%x\n",
map->data.size);
goto exit_err;
}
/* Allocate descriptor FIFO if necessary */
if (map->desc.size && map->desc.phys_base == SPS_ADDR_INVALID) {
map->alloc_desc_base = sps_mem_alloc_io(map->desc.size);
if (map->alloc_desc_base == SPS_ADDR_INVALID) {
SPS_ERR(sps, "sps:I/O memory allocation failure:0x%x\n",
map->desc.size);
goto exit_err;
}
map->desc.phys_base = map->alloc_desc_base;
map->desc.base = spsi_get_mem_ptr(map->desc.phys_base);
if (map->desc.base == NULL) {
SPS_ERR(sps,
"sps:Cannot get virt addr for I/O buffer:%pa\n",
&map->desc.phys_base);
goto exit_err;
}
}
/* Allocate data FIFO if necessary */
if (map->data.size && map->data.phys_base == SPS_ADDR_INVALID) {
map->alloc_data_base = sps_mem_alloc_io(map->data.size);
if (map->alloc_data_base == SPS_ADDR_INVALID) {
SPS_ERR(sps, "sps:I/O memory allocation failure:0x%x\n",
map->data.size);
goto exit_err;
}
map->data.phys_base = map->alloc_data_base;
map->data.base = spsi_get_mem_ptr(map->data.phys_base);
if (map->data.base == NULL) {
SPS_ERR(sps,
"sps:Cannot get virt addr for I/O buffer:%pa\n",
&map->data.phys_base);
goto exit_err;
}
}
/* Attempt to assign this connection to the client */
if (sps_rm_assign(pipe, map)) {
SPS_ERR(sps,
"sps:%s:failed to assign a connection to the client\n",
__func__);
goto exit_err;
}
/* Initialization was successful */
success = true;
exit_err:
/* If initialization failed, free resources */
if (!success) {
sps_rm_free_map_rsrc(map);
kfree(map);
return NULL;
}
return map;
}
/**
* Free connection mapping
*
* This function frees a connection mapping.
*
* @pipe - client context for SPS connection end point
*
* @return 0 on success, negative value on error
*
*/
static int sps_rm_free(struct sps_pipe *pipe)
{
struct sps_connection *map = (void *)pipe->map;
struct sps_connect *cfg = &pipe->connect;
mutex_lock(&sps_rm->lock);
/* Free this connection */
if (cfg->mode == SPS_MODE_SRC)
map->client_src = NULL;
else
map->client_dest = NULL;
pipe->map = NULL;
pipe->client_state = SPS_STATE_DISCONNECT;
sps_rm_free_map_rsrc(map);
sps_rm_remove_ref(map);
mutex_unlock(&sps_rm->lock);
return 0;
}
/**
* Allocate an SPS connection end point
*
* This function allocates resources and initializes a BAM connection.
*
* @pipe - client context for SPS connection end point
*
* @return 0 on success, negative value on error
*
*/
static int sps_rm_alloc(struct sps_pipe *pipe)
{
struct sps_connection *map;
int result = SPS_ERROR;
if (pipe->connect.sps_reserved != SPSRM_CLEAR) {
/*
* Client did not call sps_get_config() to init
* struct sps_connect, so only use legacy members.
*/
unsigned long source = pipe->connect.source;
unsigned long destination = pipe->connect.destination;
enum sps_mode mode = pipe->connect.mode;
u32 config = pipe->connect.config;
memset(&pipe->connect, SPSRM_CLEAR,
sizeof(pipe->connect));
pipe->connect.source = source;
pipe->connect.destination = destination;
pipe->connect.mode = mode;
pipe->connect.config = config;
}
if (pipe->connect.config == SPSRM_CLEAR)
pipe->connect.config = SPS_CONFIG_DEFAULT;
/*
* If configuration is not default, then client is specifying a
* connection mapping. Find a matching mapping, or fail.
* If a match is found, the client's Connect struct will be updated
* with all the mapping's values.
*/
if (pipe->connect.config != SPS_CONFIG_DEFAULT) {
if (sps_map_find(&pipe->connect)) {
SPS_ERR(sps,
"sps:%s:Failed to find connection mapping\n",
__func__);
return SPS_ERROR;
}
}
mutex_lock(&sps_rm->lock);
/* Check client state */
if (IS_SPS_STATE_OK(pipe)) {
SPS_ERR(sps,
"sps:%s:Client connection already allocated\n",
__func__);
goto exit_err;
}
/* Are the connection resources already allocated? */
map = find_unconnected(pipe);
if (map != NULL) {
/* Attempt to assign this connection to the client */
if (sps_rm_assign(pipe, map))
/* Assignment failed, so must allocate new */
map = NULL;
}
/* Allocate a new connection if necessary */
if (map == NULL) {
map = sps_rm_create(pipe);
if (map == NULL) {
SPS_ERR(sps,
"sps:%s:Failed to allocate connection\n",
__func__);
goto exit_err;
}
list_add_tail(&map->list, &sps_rm->connections_q);
}
/* Add the connection to the allocated queue */
map->refs++;
/* Initialization was successful */
result = 0;
exit_err:
mutex_unlock(&sps_rm->lock);
if (result)
return SPS_ERROR;
return 0;
}
/**
* Disconnect an SPS connection end point
*
* This function frees resources and de-initializes a BAM connection.
*
* @pipe - client context for SPS connection end point
*
* @return 0 on success, negative value on error
*
*/
static int sps_rm_disconnect(struct sps_pipe *pipe)
{
sps_rm_free(pipe);
return 0;
}
/**
* Process connection state change
*
* This function processes a connection state change.
*
* @pipe - pointer to client context
*
* @state - new state for connection
*
* @return 0 on success, negative value on error
*
*/
int sps_rm_state_change(struct sps_pipe *pipe, u32 state)
{
int auto_enable = false;
int result;
/* Allocate the pipe */
if (pipe->client_state == SPS_STATE_DISCONNECT &&
state == SPS_STATE_ALLOCATE) {
if (sps_rm_alloc(pipe)) {
SPS_ERR(pipe->bam,
"sps:Fail to allocate resource for BAM 0x%pK pipe %d\n",
pipe->bam, pipe->pipe_index);
return SPS_ERROR;
}
}
/* Configure the pipe */
if (pipe->client_state == SPS_STATE_ALLOCATE &&
state == SPS_STATE_CONNECT) {
/* Connect the BAM pipe */
struct sps_bam_connect_param params;
memset(&params, 0, sizeof(params));
params.mode = pipe->connect.mode;
if (pipe->connect.options != SPSRM_CLEAR) {
params.options = pipe->connect.options;
params.irq_gen_addr = pipe->connect.irq_gen_addr;
params.irq_gen_data = pipe->connect.irq_gen_data;
}
result = sps_bam_pipe_connect(pipe, &params);
if (result) {
SPS_ERR(pipe->bam,
"sps:Failed to connect BAM 0x%pK pipe %d\n",
pipe->bam, pipe->pipe_index);
return SPS_ERROR;
}
pipe->client_state = SPS_STATE_CONNECT;
/* Set auto-enable for system-mode connections */
if (pipe->connect.source == SPS_DEV_HANDLE_MEM ||
pipe->connect.destination == SPS_DEV_HANDLE_MEM) {
if (pipe->map->desc.size != 0 &&
pipe->map->desc.phys_base != SPS_ADDR_INVALID)
auto_enable = true;
}
}
/* Enable the pipe data flow */
if (pipe->client_state == SPS_STATE_CONNECT &&
!(state == SPS_STATE_DISABLE
|| state == SPS_STATE_DISCONNECT)
&& (state == SPS_STATE_ENABLE || auto_enable
|| (pipe->connect.options & SPS_O_AUTO_ENABLE))) {
result = sps_bam_pipe_enable(pipe->bam, pipe->pipe_index);
if (result) {
SPS_ERR(pipe->bam,
"sps:Failed to set BAM %pa pipe %d flow on\n",
&pipe->bam->props.phys_addr,
pipe->pipe_index);
return SPS_ERROR;
}
/* Is this a BAM-DMA pipe? */
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
if ((pipe->bam->props.options & SPS_BAM_OPT_BAMDMA)) {
/* Activate the BAM-DMA channel */
result = sps_dma_pipe_enable(pipe->bam,
pipe->pipe_index);
if (result) {
SPS_ERR(pipe->bam,
"sps:Failed to activate BAM-DMA pipe: %d\n",
pipe->pipe_index);
return SPS_ERROR;
}
}
#endif
pipe->client_state = SPS_STATE_ENABLE;
}
/* Disable the pipe data flow */
if (pipe->client_state == SPS_STATE_ENABLE &&
(state == SPS_STATE_DISABLE || state == SPS_STATE_DISCONNECT)) {
result = sps_bam_pipe_disable(pipe->bam, pipe->pipe_index);
if (result) {
SPS_ERR(pipe->bam,
"sps:Failed to set BAM %pa pipe %d flow off\n",
&pipe->bam->props.phys_addr,
pipe->pipe_index);
return SPS_ERROR;
}
pipe->client_state = SPS_STATE_CONNECT;
}
/* Disconnect the BAM pipe */
if (pipe->client_state == SPS_STATE_CONNECT &&
state == SPS_STATE_DISCONNECT) {
struct sps_connection *map;
struct sps_bam *bam = pipe->bam;
unsigned long flags;
u32 pipe_index;
if (pipe->connect.mode == SPS_MODE_SRC)
pipe_index = pipe->map->src.pipe_index;
else
pipe_index = pipe->map->dest.pipe_index;
if (bam->props.irq > 0)
synchronize_irq(bam->props.irq);
spin_lock_irqsave(&bam->isr_lock, flags);
pipe->disconnecting = true;
spin_unlock_irqrestore(&bam->isr_lock, flags);
result = sps_bam_pipe_disconnect(pipe->bam, pipe_index);
if (result) {
SPS_ERR(pipe->bam,
"sps:Failed to disconnect BAM %pa pipe %d\n",
&pipe->bam->props.phys_addr,
pipe->pipe_index);
return SPS_ERROR;
}
/* Clear map state */
map = (void *)pipe->map;
if (pipe->connect.mode == SPS_MODE_SRC)
map->client_src = NULL;
else if (pipe->connect.mode == SPS_MODE_DEST)
map->client_dest = NULL;
sps_rm_disconnect(pipe);
/* Clear the client state */
pipe->map = NULL;
pipe->bam = NULL;
pipe->client_state = SPS_STATE_DISCONNECT;
}
return 0;
}

View file

@ -0,0 +1,526 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved.
*/
/**
* Smart-Peripheral-Switch (SPS) internal API.
*/
#ifndef _SPSI_H_
#define _SPSI_H_
#include <linux/types.h> /* u32 */
#include <linux/list.h> /* list_head */
#include <linux/kernel.h> /* pr_info() */
#include <linux/compiler.h>
#include <linux/ratelimit.h>
#include <linux/ipc_logging.h>
#include <linux/msm-sps.h>
#include "sps_map.h"
#if defined(CONFIG_PHYS_ADDR_T_64BIT) || defined(CONFIG_ARM_LPAE)
#define SPS_LPAE (true)
#else
#define SPS_LPAE (false)
#endif
#define BAM_MAX_PIPES 31
#define BAM_MAX_P_LOCK_GROUP_NUM 31
/* Adjust for offset of struct sps_q_event */
#define SPS_EVENT_INDEX(e) ((e) - 1)
#define SPS_ERROR -1
/* BAM identifier used in log messages */
#define BAM_ID(dev) (&(dev)->props.phys_addr)
/* "Clear" value for the connection parameter struct */
#define SPSRM_CLEAR 0xccccccccUL
#define SPSRM_ADDR_CLR \
((sizeof(int) == sizeof(long)) ? 0 : (SPSRM_CLEAR << 32))
#define MAX_MSG_LEN 80
#define SPS_IPC_LOGPAGES 10
#define SPS_IPC_REG_DUMP_FACTOR 3
#define SPS_IPC_DEFAULT_LOGLEVEL 3
#define SPS_IPC_MAX_LOGLEVEL 4
/* Connection mapping control struct */
struct sps_rm {
struct list_head connections_q;
struct mutex lock;
};
/* SPS driver state struct */
struct sps_drv {
struct class *dev_class;
dev_t dev_num;
struct device *dev;
struct clk *pmem_clk;
struct clk *bamdma_clk;
struct clk *dfab_clk;
int is_ready;
/* Platform data */
phys_addr_t pipemem_phys_base;
u32 pipemem_size;
phys_addr_t bamdma_bam_phys_base;
u32 bamdma_bam_size;
phys_addr_t bamdma_dma_phys_base;
u32 bamdma_dma_size;
u32 bamdma_irq;
u32 bamdma_restricted_pipes;
/* Driver options bitflags (see SPS_OPT_*) */
u32 options;
/* Mutex to protect BAM and connection queues */
struct mutex lock;
/* BAM devices */
struct list_head bams_q;
char *hal_bam_version;
/* Connection control state */
struct sps_rm connection_ctrl;
void *ipc_log0;
void *ipc_log1;
void *ipc_log2;
void *ipc_log3;
void *ipc_log4;
u32 ipc_loglevel;
};
extern struct sps_drv *sps;
extern u32 d_type;
extern bool enhd_pipe;
extern bool imem;
extern enum sps_bam_type bam_type;
#ifdef CONFIG_DEBUG_FS
extern u8 debugfs_record_enabled;
extern u8 logging_option;
extern u8 debug_level_option;
extern u8 print_limit_option;
#define SPS_IPC(idx, dev, msg, ...) do { \
if (dev) { \
if (idx == 0) \
ipc_log_string((dev)->ipc_log0, \
"%s: " msg, __func__, ##__VA_ARGS__); \
else if (idx == 1) \
ipc_log_string((dev)->ipc_log1, \
"%s: " msg, __func__, ##__VA_ARGS__); \
else if (idx == 2) \
ipc_log_string((dev)->ipc_log2, \
"%s: " msg, __func__, ##__VA_ARGS__); \
else if (idx == 3) \
ipc_log_string((dev)->ipc_log3, \
"%s: " msg, __func__, ##__VA_ARGS__); \
else if (idx == 4) \
ipc_log_string((dev)->ipc_log4, \
"%s: " msg, __func__, ##__VA_ARGS__); \
} \
} while (0)
#define SPS_DUMP(msg, ...) do { \
SPS_IPC(4, sps, msg, ##__VA_ARGS__); \
if (sps) { \
if (sps->ipc_log4 == NULL) \
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
} \
} while (0)
#define SPS_ERR(dev, msg, ...) do { \
if (logging_option != 1) { \
if (unlikely(print_limit_option > 2)) \
pr_err_ratelimited( \
"%s: " msg, __func__, ##__VA_ARGS__); \
else \
pr_err("%s: " msg, __func__, ##__VA_ARGS__); \
} \
SPS_IPC(3, dev, msg, ##__VA_ARGS__); \
} while (0)
#define SPS_INFO(dev, msg, ...) do { \
if (logging_option != 1) { \
if (unlikely(print_limit_option > 1)) \
pr_info_ratelimited( \
"%s: " msg, __func__, ##__VA_ARGS__); \
else \
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
} \
SPS_IPC(3, dev, msg, ##__VA_ARGS__); \
} while (0)
#define SPS_DBG(dev, msg, ...) do { \
if ((unlikely(logging_option > 1)) \
&& (unlikely(debug_level_option > 3))) {\
if (unlikely(print_limit_option > 0)) \
pr_info_ratelimited( \
"%s: " msg, __func__, ##__VA_ARGS__); \
else \
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
} else \
pr_debug("%s: " msg, __func__, ##__VA_ARGS__); \
if (dev) { \
if ((dev)->ipc_loglevel <= 0) \
SPS_IPC(0, dev, msg, ##__VA_ARGS__); \
} \
} while (0)
#define SPS_DBG1(dev, msg, ...) do { \
if ((unlikely(logging_option > 1)) \
&& (unlikely(debug_level_option > 2))) {\
if (unlikely(print_limit_option > 0)) \
pr_info_ratelimited( \
"%s: " msg, __func__, ##__VA_ARGS__); \
else \
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
} else \
pr_debug("%s: " msg, __func__, ##__VA_ARGS__); \
if (dev) { \
if ((dev)->ipc_loglevel <= 1) \
SPS_IPC(1, dev, msg, ##__VA_ARGS__); \
} \
} while (0)
#define SPS_DBG2(dev, msg, ...) do { \
if ((unlikely(logging_option > 1)) \
&& (unlikely(debug_level_option > 1))) {\
if (unlikely(print_limit_option > 0)) \
pr_info_ratelimited( \
"%s: " msg, __func__, ##__VA_ARGS__); \
else \
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
} else \
pr_debug("%s: " msg, __func__, ##__VA_ARGS__); \
if (dev) { \
if ((dev)->ipc_loglevel <= 2) \
SPS_IPC(2, dev, msg, ##__VA_ARGS__); \
} \
} while (0)
#define SPS_DBG3(dev, msg, ...) do { \
if ((unlikely(logging_option > 1)) \
&& (unlikely(debug_level_option > 0))) {\
if (unlikely(print_limit_option > 0)) \
pr_info_ratelimited( \
"%s: " msg, __func__, ##__VA_ARGS__); \
else \
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
} else \
pr_debug("%s: " msg, __func__, ##__VA_ARGS__); \
if (dev) { \
if ((dev)->ipc_loglevel <= 3) \
SPS_IPC(3, dev, msg, ##__VA_ARGS__); \
} \
} while (0)
#else
#define SPS_DBG3(x...) pr_debug(x)
#define SPS_DBG2(x...) pr_debug(x)
#define SPS_DBG1(x...) pr_debug(x)
#define SPS_DBG(x...) pr_debug(x)
#define SPS_INFO(x...) pr_info(x)
#define SPS_ERR(x...) pr_err(x)
#define SPS_DUMP(x...) pr_info(x)
#endif
/* End point parameters */
struct sps_conn_end_pt {
unsigned long dev; /* Device handle of BAM */
phys_addr_t bam_phys; /* Physical address of BAM. */
u32 pipe_index; /* Pipe index */
u32 event_threshold; /* Pipe event threshold */
u32 lock_group; /* The lock group this pipe belongs to */
void *bam;
};
/* Connection bookkeeping descriptor struct */
struct sps_connection {
struct list_head list;
/* Source end point parameters */
struct sps_conn_end_pt src;
/* Destination end point parameters */
struct sps_conn_end_pt dest;
/* Resource parameters */
struct sps_mem_buffer desc; /* Descriptor FIFO */
struct sps_mem_buffer data; /* Data FIFO (BAM-to-BAM mode only) */
u32 config; /* Client specified connection configuration */
/* Connection state */
void *client_src;
void *client_dest;
int refs; /* Reference counter */
/* Dynamically allocated resources, if required */
u32 alloc_src_pipe; /* Source pipe index */
u32 alloc_dest_pipe; /* Destination pipe index */
/* Physical address of descriptor FIFO */
phys_addr_t alloc_desc_base;
phys_addr_t alloc_data_base; /* Physical address of data FIFO */
};
/* Event bookkeeping descriptor struct */
struct sps_q_event {
struct list_head list;
/* Event payload data */
struct sps_event_notify notify;
};
/* Memory heap statistics */
struct sps_mem_stats {
u32 base_addr;
u32 size;
u32 blocks_used;
u32 bytes_used;
u32 max_bytes_used;
};
enum sps_bam_type {
SPS_BAM_LEGACY,
SPS_BAM_NDP,
SPS_BAM_NDP_4K
};
#ifdef CONFIG_DEBUG_FS
/* record debug info for debugfs */
void sps_debugfs_record(const char *msg);
#endif
/* output the content of BAM-level registers */
void print_bam_reg(void *virt_addr);
/* output the content of BAM pipe registers */
void print_bam_pipe_reg(void *virt_addr, u32 pipe_index);
/* output the content of selected BAM-level registers */
void print_bam_selected_reg(void *virt_addr, u32 pipe_index);
/* output the content of selected BAM pipe registers */
void print_bam_pipe_selected_reg(void *virt_addr, u32 pipe_index);
/* output descriptor FIFO of a pipe */
void print_bam_pipe_desc_fifo(void *virt_addr, u32 pipe_index, u32 option);
/* output BAM_TEST_BUS_REG */
void print_bam_test_bus_reg(void *base, u32 tb_sel);
/* halt and un-halt a pipe */
void bam_pipe_halt(void *base, u32 pipe, bool halt);
/**
* Translate physical to virtual address
*
* This Function translates physical to virtual address.
*
* @phys_addr - physical address to translate
*
* @return virtual memory pointer
*
*/
void *spsi_get_mem_ptr(phys_addr_t phys_addr);
/**
* Allocate I/O (pipe) memory
*
* This function allocates target I/O (pipe) memory.
*
* @bytes - number of bytes to allocate
*
* @return physical address of allocated memory, or SPS_ADDR_INVALID on error
*/
phys_addr_t sps_mem_alloc_io(u32 bytes);
/**
* Free I/O (pipe) memory
*
* This function frees target I/O (pipe) memory.
*
* @phys_addr - physical address of memory to free
*
* @bytes - number of bytes to free.
*/
void sps_mem_free_io(phys_addr_t phys_addr, u32 bytes);
/**
* Find matching connection mapping
*
* This function searches for a connection mapping that matches the
* parameters supplied by the client. If a match is found, the client's
* parameter struct is updated with the values specified in the mapping.
*
* @connect - pointer to client connection parameters
*
* @return 0 if match is found, negative value otherwise
*
*/
int sps_map_find(struct sps_connect *connect);
/**
* Allocate a BAM DMA pipe
*
* This function allocates a BAM DMA pipe, and is intended to be called
* internally from the BAM resource manager. Allocation implies that
* the pipe has been referenced by a client Connect() and is in use.
*
* BAM DMA is permissive with activations, and allows a pipe to be allocated
* with or without a client-initiated allocation. This allows the client to
* specify exactly which pipe should be used directly through the Connect() API.
* sps_dma_alloc_chan() does not allow the client to specify the pipes/channel.
*
* @bam - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @dir - pipe direction
*
* @return 0 on success, negative value on error
*/
int sps_dma_pipe_alloc(void *bam, u32 pipe_index, enum sps_mode dir);
/**
* Enable a BAM DMA pipe
*
* This function enables the channel associated with a BAM DMA pipe, and
* is intended to be called internally from the BAM resource manager.
* Enable must occur *after* the pipe has been enabled so that proper
* sequencing between pipe and DMA channel enables can be enforced.
*
* @bam - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @return 0 on success, negative value on error
*
*/
int sps_dma_pipe_enable(void *bam, u32 pipe_index);
/**
* Free a BAM DMA pipe
*
* This function disables and frees a BAM DMA pipe, and is intended to be
* called internally from the BAM resource manager. This must occur *after*
* the pipe has been disabled/reset so that proper sequencing between pipe and
* DMA channel resets can be enforced.
*
* @bam_arg - pointer to BAM device descriptor
*
* @pipe_index - pipe index
*
* @return 0 on success, negative value on error
*
*/
int sps_dma_pipe_free(void *bam, u32 pipe_index);
/**
* Initialize driver memory module
*
* This function initializes the driver memory module.
*
* @pipemem_phys_base - Pipe-Memory physical base.
*
* @pipemem_size - Pipe-Memory size.
*
* @return 0 on success, negative value on error
*
*/
int sps_mem_init(phys_addr_t pipemem_phys_base, u32 pipemem_size);
/**
* De-initialize driver memory module
*
* This function de-initializes the driver memory module.
*
* @return 0 on success, negative value on error
*
*/
int sps_mem_de_init(void);
/**
* Initialize BAM DMA module
*
* This function initializes the BAM DMA module.
*
* @bam_props - pointer to BAM DMA devices BSP configuration properties
*
* @return 0 on success, negative value on error
*
*/
int sps_dma_init(const struct sps_bam_props *bam_props);
/**
* De-initialize BAM DMA module
*
* This function de-initializes the SPS BAM DMA module.
*
*/
void sps_dma_de_init(void);
/**
* Initialize BAM DMA device
*
* This function initializes a BAM DMA device.
*
* @h - BAM handle
*
* @return 0 on success, negative value on error
*
*/
int sps_dma_device_init(unsigned long h);
/**
* De-initialize BAM DMA device
*
* This function de-initializes a BAM DMA device.
*
* @h - BAM handle
*
* @return 0 on success, negative value on error
*
*/
int sps_dma_device_de_init(unsigned long h);
/**
* Initialize connection mapping module
*
* This function initializes the SPS connection mapping module.
*
* @map_props - pointer to connection mapping BSP configuration properties
*
* @options - driver options bitflags (see SPS_OPT_*)
*
* @return 0 on success, negative value on error
*
*/
int sps_map_init(const struct sps_map *map_props, u32 options);
/**
* De-initialize connection mapping module
*
* This function de-initializes the SPS connection mapping module.
*
*/
void sps_map_de_init(void);
/*
* bam_pipe_reset - reset a BAM pipe.
* @base: BAM virtual address
* @pipe: pipe index
*
* This function resets a BAM pipe.
*/
void bam_pipe_reset(void *base, u32 pipe);
/*
* bam_disable_pipe - disable a BAM pipe.
* @base: BAM virtual address
* @pipe: pipe index
*
* This function disables a BAM pipe.
*/
void bam_disable_pipe(void *base, u32 pipe);
#endif /* _SPSI_H_ */

1631
include/linux/msm-sps.h Normal file

File diff suppressed because it is too large Load diff