blob: 901d9cc2866494931e2180c2cf857658fc962696 [file] [log] [blame]
/* Copyright (c) 2011-2013, 2015, 2017. The Linux Foundation. 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 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", 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",
&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;
}