Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755327Ab1CABLr (ORCPT ); Mon, 28 Feb 2011 20:11:47 -0500 Received: from wolverine02.qualcomm.com ([199.106.114.251]:4838 "EHLO wolverine02.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755239Ab1CABLp (ORCPT ); Mon, 28 Feb 2011 20:11:45 -0500 X-IronPort-AV: E=McAfee;i="5400,1158,6271"; a="77024118" From: Kenneth Heitke To: davidb@codeaurora.org, bryanh@codeaurora.org, dwalker@fifo99.com Cc: linux-arm-msm@vger.kernel.org, linux-arm-kernel@lists.intradead.org, yanhe@codeaurora.org, palnatim@codeaurora.org, subhashj@codeaurora.org, Amir Samuelovi , Kenneth Heitke , linux-arm-kernel@lists.infradead.org (open list:ARM PORT), linux-kernel@vger.kernel.org (open list) Subject: [RFC PATCH 4/5] RFC: msm: sps: Smart Peripheral Subsystem (SPS) Resource Manager Date: Mon, 28 Feb 2011 18:11:31 -0700 Message-Id: <1298941892-25173-5-git-send-email-kheitke@codeaurora.org> X-Mailer: git-send-email 1.7.3.3 In-Reply-To: <1298941892-25173-1-git-send-email-kheitke@codeaurora.org> References: <1298941892-25173-1-git-send-email-kheitke@codeaurora.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 23085 Lines: 833 From: Amir Samuelovi Resource management for the SPS device driver. Signed-off-by: Amir Samuelov Signed-off-by: Kenneth Heitke --- arch/arm/mach-msm/sps/sps_rm.c | 806 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 806 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-msm/sps/sps_rm.c diff --git a/arch/arm/mach-msm/sps/sps_rm.c b/arch/arm/mach-msm/sps/sps_rm.c new file mode 100644 index 0000000..ec36b25 --- /dev/null +++ b/arch/arm/mach-msm/sps/sps_rm.c @@ -0,0 +1,806 @@ +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* Resource management for the SPS device driver. */ + +#include /* u32 */ +#include /* pr_info() */ +#include /* mutex */ +#include /* list_head */ +#include /* kzalloc() */ +#include /* memset */ + +#include "spsi.h" +#include "sps_core.h" + +/* "Clear" value for the connection parameter struct */ +#define SPSRM_CLEAR 0xcccccccc + +/* 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("Failed to allocate connection struct"); + + 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 && + cfg->desc.base != (void *)SPSRM_CLEAR && + (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 && + cfg->data.base != (void *)SPSRM_CLEAR && + (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; + + /* Check ownership and BAM */ + if ((cfg->mode == SPS_MODE_SRC && map->client_src != NULL) || + (cfg->mode != SPS_MODE_SRC && map->client_dest != NULL)) + /* The end point is already connected */ + 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)) + 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; + } 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; + } + pipe->map = map; + + SPS_DBG("sps:sps_rm_assign.pipe_index=%d\n", 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; + pipe->connect.desc = map->desc; + pipe->connect.data = map->data; + + 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 && + cfg->desc.base != (void *)SPSRM_CLEAR) + map->desc = cfg->desc; + + /* Did client specify data FIFO? */ + if (map->data.size != SPSRM_CLEAR && + cfg->data.phys_base != SPSRM_CLEAR && + cfg->data.base != (void *)SPSRM_CLEAR) + 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("Failed to allocate connection struct"); + 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("Invalid BAM handle: 0x%x", 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("Invalid BAM handle: 0x%x", 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("Invalid BAM endpt: dir %d src 0x%x dest 0x%x", + dir, map->src.dev, 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("Failed to alloc BAM-DMA pipe: %d", + 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("Failed to alloc BAM-DMA pipe: %d", + 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("Invalid desc FIFO size: 0x%x", 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("Invalid data FIFO size: 0x%x", 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("I/O memory allocation failure: 0x%x", + 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("Cannot get virt addr for I/O buffer: 0x%x", + 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("I/O memory allocation failure: 0x%x", + 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("Cannot get virt addr for I/O buffer: 0x%x", + map->data.phys_base); + goto exit_err; + } + } + + /* Attempt to assign this connection to the client */ + if (sps_rm_assign(pipe, map)) + 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. + */ + u32 source = pipe->connect.source; + u32 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("Failed to find connection mapping"); + return SPS_ERROR; + } + } + + mutex_lock(&sps_rm->lock); + /* Check client state */ + if (IS_SPS_STATE_OK(pipe)) { + SPS_ERR("Client connection already allocated"); + 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("Failed to allocate connection"); + 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)) + 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(¶ms, 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, ¶ms); + if (result) { + SPS_ERR("Failed to connect BAM 0x%x pipe %d", + (u32) 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("Failed to set BAM 0x%x pipe %d flow on", + 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("Failed to activate BAM-DMA pipe: %d", + 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("Failed to set BAM 0x%x pipe %d flow off", + 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; + 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; + + + result = sps_bam_pipe_disconnect(pipe->bam, pipe_index); + if (result) { + SPS_ERR("Failed to disconnect BAM 0x%x pipe %d", + 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; +} -- 1.7.3.3 Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/