The debugging functions in SPS driver are enhanced as follows: 1> Change some logging output from pr_info() to pr_debug() to reduce log amount. 2> Formalize the log content since some logs did not have the keyword which shows they are from SPS driver. This modification can help people find the error or other information from SPS driver more conveniently. 3> SPS driver did not output error messages in some places where an error is captured. Add error message output for these places. 4> SPS driver is used by some peripherals (such as SDCC) which have high throughput. When DEBUG level logging is enabled, the log output is tremendous and sometimes even hinders the analysis of the log, although some log messages are very helpful to the debugging of particular issues. Thus, add fine-grained DEBUG level log output control via debugfs. 5> Add the options via debugfs which dump the content of selected BAM registers. This can help analyze the BAM-related issues without additional software tools. Change-Id: Ie97dc5d3b2736ea840125dad978e81abb960b27a Signed-off-by: Yan He <yanhe@codeaurora.org>
138 lines
3.3 KiB
C
138 lines
3.3 KiB
C
/* Copyright (c) 2011-2012, 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.
|
|
*/
|
|
|
|
/**
|
|
* Connection mapping table managment 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: %d mappings", 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:Cannot get virt addr for I/O buffer: 0x%x",
|
|
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:Can't get virt addr for I/O buffer: 0x%x",
|
|
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;
|
|
}
|