| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (c) 2011-2013, 2015, 2017-2018, 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", 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; |
| } |