M7350/qcom-opensource/kernel/kernel-tests/glink/glink_loopback_xprt.c
2024-09-09 08:57:42 +00:00

1340 lines
40 KiB
C

/* Copyright (c) 2014-2015, 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.
*/
#include <linux/ipc_logging.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <soc/qcom/smem.h>
#include <soc/qcom/glink.h>
#include <soc/qcom/tracer_pkt.h>
#include "glink_core_if.h"
#include "glink_loopback_xprt.h"
#include "glink_private.h"
#include "glink_xprt_if.h"
enum {
INFO_MASK = 1U << 0,
DEBUG_MASK = 1U << 1,
PERF_MASK = 1U << 2,
};
static int glx_debug_mask;
module_param_named(xprt_debug_mask, glx_debug_mask,
int, S_IRUGO | S_IWUSR | S_IWGRP);
/*
* SMEM and interrupt simulation.
*
* 0 = disable
* >0 = enabled with specified interrupt latency in us
*/
static unsigned glx_smem_rw_int_latency_us;
module_param_named(smem_rw_enable, glx_smem_rw_int_latency_us,
uint, S_IRUGO | S_IWUSR | S_IWGRP);
static void *smem_item_addr;
#define GLX_PERF(fmt, args...) do { \
if (glx_debug_mask & PERF_MASK) \
GLINK_IPC_LOG_STR("<LL> " fmt, args); \
} while (0)
#define GLX_INFO(x...) do { \
if (glx_debug_mask & INFO_MASK) \
GLINK_IPC_LOG_STR("<LL> " x); \
} while (0)
#define GLX_INFO_PERF(fmt, args...) do { \
if (glx_debug_mask & (INFO_MASK | PERF_MASK)) \
GLINK_IPC_LOG_STR("<LL> " fmt, args); \
} while (0)
#define GLX_DBG(x...) do { \
if (glx_debug_mask & DEBUG_MASK) \
GLINK_IPC_LOG_STR("<LL> " x); \
} while (0)
#define GLX_ERR(x...) do { \
if (!(glx_debug_mask & PERF_MASK)) \
pr_err("<LL> " x); \
GLINK_IPC_LOG_STR("<LL> " x); \
} while (0)
static struct glink_loopback_xprt loopback_xprt;
static uint32_t negotiate_features_v1(struct glink_transport_if *if_ptr,
const struct glink_core_version *version_ptr,
uint32_t features);
static void deinit_loopback_xprt_lists(void);
/* Versions data structure, used in version negotiation. */
static struct glink_core_version versions[] = {
{1, 0x00, negotiate_features_v1},
{2, 0x22, negotiate_features_v1},
{5, 0x55, negotiate_features_v1},
};
/**
* struct cmd_handler_info - Structure that stores the command handler data
* @type: The command type
* @cmd_handler: Pointer to the command handler function
*/
struct cmd_handler_info {
enum cmd_type type;
int (*cmd_handler)(struct glink_loopback_xprt_cmd *cmd);
};
static int handle_open_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_close_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_version_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_version_ack_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_set_version_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_open_ack_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_close_ack_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_rx_intent_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_rx_done_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_rx_intent_req_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_rx_intent_req_ack_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_data_cmd(struct glink_loopback_xprt_cmd *cmd);
static int handle_sigs_set_cmd(struct glink_loopback_xprt_cmd *cmd);
struct cmd_handler_info cmd_handler_tbl[] = {
{OPEN, handle_open_cmd},
{CLOSE, handle_close_cmd},
{VERSION, handle_version_cmd},
{VERSION_ACK, handle_version_ack_cmd},
{SET_VERSION, handle_set_version_cmd},
{OPEN_ACK, handle_open_ack_cmd},
{CLOSE_ACK, handle_close_ack_cmd},
{RX_INTENT, handle_rx_intent_cmd},
{RX_DONE, handle_rx_done_cmd},
{RX_INTENT_REQ, handle_rx_intent_req_cmd},
{RX_INTENT_REQ_ACK, handle_rx_intent_req_ack_cmd},
{DATA, handle_data_cmd},
{SIGS_SET, handle_sigs_set_cmd},
};
union fifo_mem {
uint64_t u64;
uint8_t u8;
};
/**
* glink_loopback_xprt_copy_to_smem() - Copy data to SMEM
* @src: The buffer to copy from
* @num_bytes: The number of bytes to copy
*/
static void glink_loopback_xprt_copy_to_smem(void *src, size_t num_bytes)
{
union fifo_mem *temp_dst = (union fifo_mem *)smem_item_addr;
union fifo_mem *temp_src = (union fifo_mem *)src;
uintptr_t mask = sizeof(union fifo_mem) - 1;
if (unlikely(!smem_item_addr)) {
smem_item_addr = smem_alloc(SMEM_ID_VENDOR0, 8192, 0,
SMEM_ANY_HOST_FLAG);
if (!smem_item_addr) {
GLX_ERR("%s: Cannot copy to SMEM as configured\n",
__func__);
return;
}
temp_dst = (union fifo_mem *)smem_item_addr;
}
if (!temp_src || !temp_dst) {
GLX_ERR("%s: %p %p\n", __func__, temp_src, temp_dst);
return;
}
GLX_INFO("%s: Copying %zu bytes to SMEM\n", __func__, num_bytes);
while ((uintptr_t)temp_dst & mask && num_bytes) {
__raw_writeb_no_log(temp_src->u8, temp_dst);
temp_src = (union fifo_mem *)((uintptr_t)temp_src + 1);
temp_dst = (union fifo_mem *)((uintptr_t)temp_dst + 1);
num_bytes--;
}
while (num_bytes >= sizeof(union fifo_mem)) {
__raw_writeq_no_log(temp_src->u64, temp_dst);
temp_dst++;
temp_src++;
num_bytes -= sizeof(union fifo_mem);
}
while (num_bytes--) {
__raw_writeb_no_log(temp_src->u8, temp_dst);
temp_src = (union fifo_mem *)((uintptr_t)temp_src + 1);
temp_dst = (union fifo_mem *)((uintptr_t)temp_dst + 1);
}
}
/**
* glink_loopback_xprt_copy_from_smem() - Copy data from SMEM
* @dest: The destination buffer
* @num_bytes: The number of bytes to copy
*/
static void glink_loopback_xprt_copy_from_smem(void *dest, size_t num_bytes)
{
union fifo_mem *temp_dst = (union fifo_mem *)dest;
union fifo_mem *temp_src = (union fifo_mem *)smem_item_addr;
uintptr_t mask = sizeof(union fifo_mem) - 1;
if (unlikely(!smem_item_addr))
return;
if (!temp_src || !temp_dst) {
GLX_ERR("%s: %p %p\n", __func__, temp_src, temp_dst);
return;
}
GLX_INFO("%s: Copying %zu bytes from SMEM\n", __func__, num_bytes);
while ((uintptr_t)temp_src & mask && num_bytes) {
temp_dst->u8 = __raw_readb_no_log(temp_src);
temp_src = (union fifo_mem *)((uintptr_t)temp_src + 1);
temp_dst = (union fifo_mem *)((uintptr_t)temp_dst + 1);
num_bytes--;
}
while (num_bytes >= sizeof(union fifo_mem)) {
temp_dst->u64 = __raw_readq_no_log(temp_src);
temp_dst++;
temp_src++;
num_bytes -= sizeof(union fifo_mem);
}
while (num_bytes--) {
temp_dst->u8 = __raw_readb_no_log(temp_src);
temp_src = (union fifo_mem *)((uintptr_t)temp_src + 1);
temp_dst = (union fifo_mem *)((uintptr_t)temp_dst + 1);
}
}
/**
* simulate_smem_loopback() - Simulate a buffer round trip through SMEM
* @buffer: The buffer to be sent in the simulation
* @num_bytes: The number of bytes to send
*/
static void simulate_smem_loopback(void *buffer, size_t num_bytes)
{
if (!glx_smem_rw_int_latency_us)
return;
glink_loopback_xprt_copy_to_smem(buffer, num_bytes);
udelay(glx_smem_rw_int_latency_us);
glink_loopback_xprt_copy_from_smem(buffer, num_bytes);
}
/**
* negotiate_features_v1() - Get feature set
* @if_ptr: Pointer to interface instance
* @version_ptr: Pointer to G-Link core version instance
* @features: Features
*
* Return: Features masked off by the supported features
*/
static uint32_t negotiate_features_v1(struct glink_transport_if *if_ptr,
const struct glink_core_version *version_ptr,
uint32_t features)
{
return features & version_ptr->features;
}
/**
* lookup_ch_map_info() - Lookup channel map info given a channel name
* @name: The name of the channel
*
* Return: The channel map info if found, NULL otherwise
*/
static struct ch_map_info *lookup_ch_map_info(char *name)
{
struct ch_map_info *temp_map;
list_for_each_entry(temp_map, &loopback_xprt.ch_map, list) {
if (!strncmp(temp_map->ch_name, name, MAX_NAME_LEN))
return temp_map;
}
return NULL;
}
/**
* handle_open_cmd() - Handle OPEN command
* @cmd: The command structure
*
* Return: 0 on success, standard error codes otherwise
*/
static int handle_open_cmd(struct glink_loopback_xprt_cmd *cmd)
{
char ch_name[MAX_NAME_LEN];
struct ch_map_info *temp_map;
char *temp;
int is_client = 1;
int lcid;
strlcpy(ch_name, cmd->open.name, MAX_NAME_LEN);
lcid = cmd->open.lcid;
temp = strnstr(ch_name, "_CLNT", MAX_NAME_LEN);
if (!temp) {
is_client = 0;
temp = strnstr(ch_name, "_SRV", MAX_NAME_LEN);
}
if (!temp) {
GLX_ERR("::%s[%d:] %s: OPEN Invalid ch_name\n", ch_name, lcid,
__func__);
return -EINVAL;
}
*temp = '\0';
mutex_lock(&loopback_xprt.ch_map_lock);
temp_map = lookup_ch_map_info(ch_name);
if (!temp_map) {
temp_map = kzalloc(sizeof(struct ch_map_info), GFP_KERNEL);
if (!temp_map) {
mutex_unlock(&loopback_xprt.ch_map_lock);
GLX_ERR("::%s[%d:] %s: OPEN Error allocating ch_map\n",
ch_name, lcid, __func__);
return -ENOMEM;
}
INIT_LIST_HEAD(&temp_map->list);
strlcpy(temp_map->ch_name, ch_name, MAX_NAME_LEN);
temp_map->ch1_lcid = cmd->open.lcid;
list_add_tail(&temp_map->list, &loopback_xprt.ch_map);
} else {
if (!temp_map->ch1_lcid) {
temp_map->ch1_lcid = cmd->open.lcid;
} else if (!temp_map->ch2_lcid) {
temp_map->ch2_lcid = cmd->open.lcid;
} else {
mutex_unlock(&loopback_xprt.ch_map_lock);
GLX_ERR("::%s[%d:] %s: OPEN Channel in invalid state\n",
ch_name, lcid, __func__);
return -EFAULT;
}
}
if (is_client)
strlcat(ch_name, "_SRV", MAX_NAME_LEN);
else
strlcat(ch_name, "_CLNT", MAX_NAME_LEN);
loopback_xprt.if_ptr.glink_core_if_ptr->rx_cmd_ch_remote_open(
&loopback_xprt.if_ptr, cmd->open.lcid, ch_name, LLOOP_XPRT_ID);
if (temp_map->ch1_lcid && temp_map->ch2_lcid)
GLX_INFO("::%s[%x:] %s: OPEN Opened %x\n", temp_map->ch_name,
temp_map->ch1_lcid, __func__, temp_map->ch2_lcid);
mutex_unlock(&loopback_xprt.ch_map_lock);
return 0;
}
/**
* handle_open_ack_cmd() - Handle OPEN_ACK command
* @cmd: The command structure
*
* Return: 0
*/
static int handle_open_ack_cmd(struct glink_loopback_xprt_cmd *cmd)
{
loopback_xprt.if_ptr.glink_core_if_ptr->rx_cmd_ch_open_ack(
&loopback_xprt.if_ptr, cmd->open_ack.lcid, LLOOP_XPRT_ID);
return 0;
}
/**
* handle_close_cmd() - Handle CLOSE command
* @cmd: The command structure
*
* Return: 0
*/
static int handle_close_cmd(struct glink_loopback_xprt_cmd *cmd)
{
struct ch_map_info *temp_map;
mutex_lock(&loopback_xprt.ch_map_lock);
list_for_each_entry(temp_map, &loopback_xprt.ch_map, list) {
if (temp_map->ch1_lcid == cmd->close.lcid) {
temp_map->ch1_lcid = 0;
break;
} else if (temp_map->ch2_lcid == cmd->close.lcid) {
temp_map->ch2_lcid = 0;
break;
}
}
loopback_xprt.if_ptr.glink_core_if_ptr->rx_cmd_ch_remote_close(
&loopback_xprt.if_ptr, cmd->close.lcid);
GLX_INFO("::%s[%x:] %s CLOSE Closed %x\n", temp_map->ch_name,
temp_map->ch1_lcid, __func__, temp_map->ch2_lcid);
mutex_unlock(&loopback_xprt.ch_map_lock);
return 0;
}
/**
* handle_close_ack_cmd() - Handle CLOSE_ACK command
* @cmd: The command structure
*
* Return: 0
*/
static int handle_close_ack_cmd(struct glink_loopback_xprt_cmd *cmd)
{
loopback_xprt.if_ptr.glink_core_if_ptr->rx_cmd_ch_close_ack(
&loopback_xprt.if_ptr, cmd->close_ack.lcid);
return 0;
}
/**
* handle_version_cmd() - Handle VERSION command
* @cmd: The command structure
*
* Return: 0 on success, standard error codes otherwise
*/
static int handle_version_cmd(struct glink_loopback_xprt_cmd *cmd)
{
int count = ARRAY_SIZE(versions);
if (cmd->version.version != versions[count-1].version &&
cmd->version.features != versions[count-1].features) {
GLX_ERR("%s: VERSION %x:%x version/features mismatch\n",
__func__, cmd->version.version, cmd->version.features);
return -EINVAL;
}
loopback_xprt.if_ptr.glink_core_if_ptr->rx_cmd_version(
&loopback_xprt.if_ptr, cmd->version.version,
cmd->version.features);
return 0;
}
/**
* handle_version_ack_cmd() - Handle VERSION_ACK command
* @cmd: The command structure
*
* Return: 0 on success, standard error codes otherwise
*/
static int handle_version_ack_cmd(struct glink_loopback_xprt_cmd *cmd)
{
int count = ARRAY_SIZE(versions);
if (cmd->version.version != versions[count-1].version &&
cmd->version.features != versions[count-1].features) {
GLX_ERR("%s: VERSION_ACK %x:%x version/features mismatch\n",
__func__, cmd->version.version, cmd->version.features);
return -EINVAL;
}
loopback_xprt.if_ptr.glink_core_if_ptr->rx_cmd_version_ack(
&loopback_xprt.if_ptr, cmd->version.version,
cmd->version.features);
return 0;
}
/**
* handle_set_version_cmd() - Handle SET_VERSION command
* @cmd: The command structure
*
* Return: 0 on success, standard error codes otherwise
*/
static int handle_set_version_cmd(struct glink_loopback_xprt_cmd *cmd)
{
int count = ARRAY_SIZE(versions);
if (cmd->version.version != versions[count-1].version &&
cmd->version.features != versions[count-1].features) {
GLX_ERR("%s: SET_VERSION %x:%x version/features mismatch\n",
__func__, cmd->version.version, cmd->version.features);
return -EINVAL;
}
GLX_INFO("%s: %x:%x\n", __func__, cmd->version.version,
cmd->version.features);
return 0;
}
/**
* handle_rx_intent_cmd() - Handle RX_INTENT command
* @cmd: The command structure
*
* Return: 0
*/
static int handle_rx_intent_cmd(struct glink_loopback_xprt_cmd *cmd)
{
loopback_xprt.if_ptr.glink_core_if_ptr->rx_cmd_remote_rx_intent_put(
&loopback_xprt.if_ptr, cmd->rx_intent.lcid, cmd->rx_intent.id,
cmd->rx_intent.size);
GLX_INFO("lcid: %d %s: L[%d]:%d RX_INTENT\n", cmd->rx_intent.lcid,
__func__, cmd->rx_intent.id, cmd->rx_intent.size);
return 0;
}
/**
* handle_rx_done_cmd() - Handle RX_DONE command
* @cmd: The command structure
*
* Return: 0
*/
static int handle_rx_done_cmd(struct glink_loopback_xprt_cmd *cmd)
{
loopback_xprt.if_ptr.glink_core_if_ptr->rx_cmd_tx_done(
&loopback_xprt.if_ptr, cmd->rx_done.lcid, cmd->rx_done.liid,
cmd->rx_done.reuse);
GLX_INFO("rcid: %u %s: RX_DONE L[%u]:\n",
cmd->rx_done.lcid, __func__, cmd->rx_done.liid);
return 0;
}
/**
* handle_rx_intent_req_cmd() - Handle RX_INTENT_REQ command
* @cmd: The command structure
*
* Return: 0
*/
static int handle_rx_intent_req_cmd(struct glink_loopback_xprt_cmd *cmd)
{
loopback_xprt.if_ptr.glink_core_if_ptr->rx_cmd_remote_rx_intent_req(
&loopback_xprt.if_ptr, cmd->rx_intent_req.lcid,
cmd->rx_intent_req.size);
GLX_INFO("lcid: %d %s: RX_INTENT_REQ size: %d\n",
cmd->rx_intent_req.lcid, __func__,
cmd->rx_intent_req.size);
return 0;
}
/**
* handle_rx_intent_req_ack_cmd() - Handle RX_INTENT_REQ_ACK command
* @cmd: The command structure
*
* Return: 0
*/
static int handle_rx_intent_req_ack_cmd(struct glink_loopback_xprt_cmd *cmd)
{
loopback_xprt.if_ptr.glink_core_if_ptr->rx_cmd_rx_intent_req_ack(
&loopback_xprt.if_ptr, cmd->rx_intent_req_ack.lcid,
cmd->rx_intent_req_ack.granted);
GLX_INFO("lcid: %d %s: RX_INTENT_REQ_ACK granted: %d\n",
cmd->rx_intent_req_ack.lcid, __func__,
cmd->rx_intent_req_ack.granted);
return 0;
}
/**
* handle_data_cmd() - Handle DATA command
* @cmd: The command structure
*
* Return: 0
*/
static int handle_data_cmd(struct glink_loopback_xprt_cmd *cmd)
{
struct glink_core_rx_intent *rx_intent_ptr;
GLX_INFO_PERF("rcid: %u %s: start RX L[%u]:%u data[%p] size[%u]\n",
cmd->data.lcid, __func__, cmd->data.riid, cmd->data.size,
cmd->data.data, cmd->data.size);
if (cmd->data.tracer_pkt)
tracer_pkt_log_event((void *)(cmd->data.data),
GLINK_XPRT_RX);
rx_intent_ptr = loopback_xprt.if_ptr.glink_core_if_ptr->rx_get_pkt_ctx(
&loopback_xprt.if_ptr, cmd->data.lcid, cmd->data.riid);
if (rx_intent_ptr->data) {
GLX_ERR(
"lcid: %d %s: R[%d]:%d DATA size_rem: %d already exists\n",
cmd->data.lcid, __func__, cmd->data.riid, cmd->data.size,
cmd->data.size_remaining);
}
rx_intent_ptr->tracer_pkt = cmd->data.tracer_pkt;
rx_intent_ptr->data = (void *)cmd->data.data;
rx_intent_ptr->iovec = cmd->data.iovec;
rx_intent_ptr->pkt_size = cmd->data.size;
rx_intent_ptr->vprovider = cmd->data.vbuf_provider;
rx_intent_ptr->pprovider = cmd->data.pbuf_provider;
loopback_xprt.if_ptr.glink_core_if_ptr->rx_put_pkt_ctx(
&loopback_xprt.if_ptr, cmd->data.lcid, rx_intent_ptr,
cmd->data.size_remaining == 0 ? true : false);
return 0;
}
/**
* handle_sigs_set_cmd() - Handle SIGS_SET command
* @cmd: The command structure
*
* Return: 0
*/
static int handle_sigs_set_cmd(struct glink_loopback_xprt_cmd *cmd)
{
loopback_xprt.if_ptr.glink_core_if_ptr->rx_cmd_remote_sigs(
&loopback_xprt.if_ptr, cmd->sigs_set.lcid, cmd->sigs_set.sigs);
GLX_INFO("lcid: %d %s: SIGS_SET: 0x%x\n",
cmd->sigs_set.lcid, __func__,
cmd->sigs_set.sigs);
return 0;
}
/**
* ll_cmd_worker() - Calls command handlers for commands in the command list
* @work: The work structure
*
* This worker function iterates through the list of commands for the loopback
* transport and calls the appropriate command handler for each one.
*/
static void ll_cmd_worker(struct work_struct *work)
{
struct glink_loopback_xprt_cmd *cmd;
int ret;
while (1) {
mutex_lock(&loopback_xprt.tx_cmds_lock);
if (list_empty(&loopback_xprt.tx_cmds)) {
mutex_unlock(&loopback_xprt.tx_cmds_lock);
break;
}
cmd = list_first_entry(&loopback_xprt.tx_cmds,
struct glink_loopback_xprt_cmd, element);
list_del(&cmd->element);
mutex_unlock(&loopback_xprt.tx_cmds_lock);
if (cmd->type < ARRAY_SIZE(cmd_handler_tbl))
ret = cmd_handler_tbl[cmd->type].cmd_handler(cmd);
else
GLX_ERR("%s: Unknown cmd %d\n", __func__, cmd->type);
kfree(cmd);
}
}
/**
* ssr() - Perform any necessary cleanup at the transport level
* @if_ptr: Pointer to interface instance
*
* Return: 0 on success, standard error codes otherwise
*/
static int ssr(struct glink_transport_if *if_ptr)
{
loopback_xprt.if_ptr.glink_core_if_ptr->link_down(
&loopback_xprt.if_ptr);
deinit_loopback_xprt_lists();
return 0;
}
/**
* tx_cmd_version() - Transmit a version command for local negotiation
* @if_ptr: Pointer to interface instance
* @version: Version
* @features: Features
*
* Expected response is glink_core_if::rx_cmd_version_ack.
*/
static void tx_cmd_version(struct glink_transport_if *if_ptr,
uint32_t version,
uint32_t features)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return;
}
GLX_DBG("%s: %x:%08x\n", __func__, version, features);
cmd->type = VERSION;
cmd->version.version = version;
cmd->version.features = features;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
}
/**
* tx_cmd_version_ack() - Transmit a version ack for remote negotiation
* @if_ptr: Pointer to interface instance
* @version: Version
* @features: Features
*/
static void tx_cmd_version_ack(struct glink_transport_if *if_ptr,
uint32_t version, uint32_t features)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return;
}
cmd->type = VERSION_ACK;
cmd->version.version = version;
cmd->version.features = features;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
}
/**
* set_version() - Signals that negotiation is complete
* @if_ptr: Pointer to interface instance
* @version: Version
* @features: Features
*
* Signals that negotiation is complete and the transport can now do version-
* specific initialization.
*
* Return: The supported capabilities of the transport.
*/
static uint32_t set_version(struct glink_transport_if *if_ptr, uint32_t version,
uint32_t features)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return 0;
}
/*
* This isn't a command that goes out over the wire - it is just used
* internally to configure the transport.
*/
cmd->type = SET_VERSION;
cmd->version.version = version;
cmd->version.features = features;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
return GCAP_TRACER_PKT;
}
/**
* tx_cmd_ch_open() - Sends the open command
* @if_ptr: Pointer to interface instance
* @lcid: Local channel ID
* @name: Channel name
* @req_xprt: The transport the core would like to migrate this channel to.
*
* The expected response is glink_core_if::rx_cmd_ch_open_ack.
*
* Return: 0 on success, standard error codes otherwise
*/
static int tx_cmd_ch_open(struct glink_transport_if *if_ptr, uint32_t lcid,
const char *name, uint16_t req_xprt)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return -ENOMEM;
}
GLX_INFO_PERF("::%s[%d:] %s: start OPEN\n", name, lcid, __func__);
cmd->type = OPEN;
cmd->open.lcid = lcid;
strlcpy(cmd->open.name, name, MAX_NAME_LEN);
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
GLX_INFO_PERF("::%s[%d:] %s: finish OPEN\n", name, lcid, __func__);
return 0;
}
/**
* tx_cmd_ch_close() - Sends the close command
* @if_ptr: Pointer to interface instance
* @lcid: Local channel ID
*
* The expected response is glink_core_if::rx_cmd_ch_close_ack.
*
* Return: 0 on success, standard error codes otherwise
*/
static int tx_cmd_ch_close(struct glink_transport_if *if_ptr, uint32_t lcid)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return -ENOMEM;
}
GLX_INFO_PERF("lcid: %d, %s: start CLOSE\n", lcid, __func__);
cmd->type = CLOSE;
cmd->close.lcid = lcid;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
GLX_INFO_PERF("lcid: %d, %s: finish CLOSE\n", lcid, __func__);
return 0;
}
/**
* tx_cmd_ch_remote_open_ack() - Sends the remote open ACK command
* @if_ptr: Pointer to interface instance
* @rcid: Remote channel ID
* @xprt_resp: The response to a transport migration request.
*
* Sends the remote open ACK command in response to receiving
* glink_core_if::rx_cmd_ch_remote_open.
*/
static void tx_cmd_ch_remote_open_ack(struct glink_transport_if *if_ptr,
uint32_t rcid, uint16_t xprt_resp)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return;
}
GLX_INFO("rcid: %d, %s: start OPEN_ACK\n", rcid, __func__);
cmd->type = OPEN_ACK;
cmd->open_ack.lcid = rcid;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
GLX_INFO("rcid: %d, %s: finish OPEN_ACK\n", rcid, __func__);
}
/**
* tx_cmd_ch_remote_close_ack() - Sends the remote open ACK command
* @if_ptr: Pointer to interface instance
* @rcid: Remote channel ID
*
* Sends the remote open ACK command in response to receiving
* glink_core_if::rx_cmd_ch_remote_close.
*/
static void tx_cmd_ch_remote_close_ack(struct glink_transport_if *if_ptr,
uint32_t rcid)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return;
}
GLX_INFO("rcid: %d, %s: start CLOSE_ACK\n", rcid, __func__);
cmd->type = CLOSE_ACK;
cmd->close_ack.lcid = rcid;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
GLX_INFO("rcid: %d, %s: finish CLOSE_ACK\n", rcid, __func__);
}
/**
* allocate_rx_intent - Allocate/reserve space for RX Intent
* @if_ptr: The transport the intent is associated with
* @size: Size of intent
* @intent: Pointer to the intent structure
*
* Note that returning NULL for the pointer is valid (it means that space has
* been reserved, but the actual pointer will be provided later).
*
* Return: 0 on success, standard error codes otherwise
*/
static int allocate_rx_intent(struct glink_transport_if *if_ptr, size_t size,
struct glink_core_rx_intent *intent)
{
if (!intent)
return -EINVAL;
intent->data = NULL;
intent->iovec = NULL;
intent->vprovider = NULL;
intent->pprovider = NULL;
return 0;
}
/**
* deallocate_rx_intent() - Deallocate space created for RX Intent
* @if_ptr: The transport the intent is associated with
* @intent: Pointer to the intent structure
*
* Return: 0 on success, standard error codes otherwise
*/
static int deallocate_rx_intent(struct glink_transport_if *if_ptr,
struct glink_core_rx_intent *intent)
{
if (!intent)
return -EINVAL;
intent->data = NULL;
intent->iovec = NULL;
intent->vprovider = NULL;
intent->pprovider = NULL;
return 0;
}
/**
* reuse_rx_intent() - Reuse space created for RX Intent
* @if_ptr: The transport the intent is associated with
* @intent: Pointer to the intent structure
*
* Return: 0 on success, standard error codes otherwise
*/
static int reuse_rx_intent(struct glink_transport_if *if_ptr,
struct glink_core_rx_intent *intent)
{
if (!intent)
return -EINVAL;
intent->data = NULL;
intent->iovec = NULL;
intent->vprovider = NULL;
intent->pprovider = NULL;
return 0;
}
/**
* tx_cmd_local_rx_intent() - Send receive intent ID
* @if_ptr: Pointer to interface instance
* @lcid: Local channel ID
* @size: Size of receive intent
* @liid: Local intent ID
*
* Return: 0 on success, standard error codes otherwise
*/
static int tx_cmd_local_rx_intent(struct glink_transport_if *if_ptr,
uint32_t lcid, size_t size, uint32_t liid)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return -ENOMEM;
}
GLX_INFO("lcid: %d %s: start L[%d]:%zu RX_INTENT\n", lcid,
__func__, liid, size);
cmd->type = RX_INTENT;
cmd->rx_intent.lcid = lcid;
cmd->rx_intent.size = size;
cmd->rx_intent.id = liid;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
GLX_INFO("lcid: %d %s: finish L[%d]:%zu RX_INTENT\n", lcid,
__func__, liid, size);
return 0;
}
/**
* tx_cmd_local_rx_done() - Send receive-done command
* @if_ptr: Pointer to interface instance
* @lcid: Local channel ID
* @liid: Local intent ID
* @reuse: Reuse the consumed intent
*/
static void tx_cmd_local_rx_done(struct glink_transport_if *if_ptr,
uint32_t lcid, uint32_t liid, bool reuse)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return;
}
GLX_INFO("lcid: %d %s: L[%d]:\n", lcid, __func__, liid);
cmd->type = RX_DONE;
cmd->rx_done.lcid = lcid;
cmd->rx_done.liid = liid;
cmd->rx_done.reuse = reuse;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
GLX_INFO("lcid: %d %s: end (Success) RX_DONE L[%d]:\n", lcid,
__func__, liid);
}
/**
* tx() - Send a data packet
* @if_ptr: Pointer to interface instance
* @lcid: Local channel ID
* @pctx: Packet TX context
*
* Return: The number of bytes transmitted on success, standard error codes
* otherwise
*/
static int tx(struct glink_transport_if *if_ptr, uint32_t lcid,
struct glink_core_tx_pkt *pctx)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return -ENOMEM;
}
GLX_INFO_PERF("lcid: %u %s: R[%u]:%u data[%p] size[%u]\n",
lcid, __func__, pctx->riid, pctx->size, pctx->data, pctx->size);
cmd->type = DATA;
cmd->data.lcid = lcid;
cmd->data.data = (const char *)pctx->data;
cmd->data.iovec = pctx->iovec;
cmd->data.riid = pctx->riid;
cmd->data.size = pctx->size;
pctx->size_remaining -= pctx->size;
cmd->data.size_remaining = pctx->size_remaining;
cmd->data.vbuf_provider = pctx->vprovider;
cmd->data.pbuf_provider = pctx->pprovider;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
simulate_smem_loopback((void *)cmd->data.data, (size_t)cmd->data.size);
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
GLX_INFO_PERF(
"lcid: %u %s: end (Success) TX R[%u]:%u data[%p] size[%u]\n",
lcid, __func__, pctx->riid, pctx->size, pctx->data, pctx->size);
return pctx->size;
}
/**
* tx_cmd_tracer_pkt() - Send a tracer packet
* @if_ptr: Pointer to interface instance
* @lcid: Local channel ID
* @pctx: Packet TX context
*
* Return: The number of bytes transmitted on success, standard error codes
* otherwise
*/
static int tx_cmd_tracer_pkt(struct glink_transport_if *if_ptr, uint32_t lcid,
struct glink_core_tx_pkt *pctx)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return -ENOMEM;
}
GLX_INFO_PERF("lcid: %u %s: R[%u]:%u data[%p] size[%u]\n",
lcid, __func__, pctx->riid, pctx->size, pctx->data, pctx->size);
cmd->type = DATA;
cmd->data.lcid = lcid;
cmd->data.tracer_pkt = true;
cmd->data.data = (const char *)pctx->data;
cmd->data.iovec = pctx->iovec;
cmd->data.riid = pctx->riid;
cmd->data.size = pctx->size;
pctx->size_remaining -= pctx->size;
cmd->data.size_remaining = pctx->size_remaining;
cmd->data.vbuf_provider = pctx->vprovider;
cmd->data.pbuf_provider = pctx->pprovider;
tracer_pkt_log_event((void *)(pctx->data), GLINK_XPRT_TX);
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
simulate_smem_loopback((void *)cmd->data.data, (size_t)cmd->data.size);
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
GLX_INFO_PERF(
"lcid: %u %s: end (Success) TX R[%u]:%u data[%p] size[%u]\n",
lcid, __func__, pctx->riid, pctx->size, pctx->data, pctx->size);
return pctx->size;
}
/**
* tx_cmd_remote_rx_intent_req_ack() - Transmit the ack for remote
* RX intent request
* @if_ptr: Pointer to transport interface
* @lcid: Local channel ID
* @granted: Intent grant status
*
* This function transmits the ack for the remote request for an RX intent.
*
* Return: 0 on success, standard error codes otherwise
*/
static int tx_cmd_remote_rx_intent_req_ack(struct glink_transport_if *if_ptr,
uint32_t lcid, bool granted)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return -ENOMEM;
}
GLX_INFO("lcid: %d %s: start RX_INTENT_REQ_ACK granted: %d\n",
lcid, __func__, granted);
cmd->type = RX_INTENT_REQ_ACK;
cmd->rx_intent_req_ack.lcid = lcid;
cmd->rx_intent_req_ack.granted = granted;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
GLX_INFO("lcid: %d %s: finish RX_INTENT_REQ_ACK granted: %d\n",
lcid, __func__, granted);
return 0;
}
/**
* tx_cmd_rx_intent_req() - Transmit the RX intent request
* @if_ptr: Pointer to transport interface
* @lcid: Local channel ID
* @size: Size of the intent
*
* This function transmits the request for an RX intent to the remote side.
*
* Return: 0 on success, standard error codes otherwise
*/
static int tx_cmd_rx_intent_req(struct glink_transport_if *if_ptr,
uint32_t lcid, size_t size)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return -ENOMEM;
}
GLX_INFO("lcid: %d %s: start L[]:%zu RX_INTENT_REQ\n", lcid,
__func__, size);
cmd->type = RX_INTENT_REQ;
cmd->rx_intent_req.lcid = lcid;
cmd->rx_intent_req.size = size;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
GLX_INFO("lcid: %d %s: finish L[]:%zu RX_INTENT_REQ\n", lcid,
__func__, size);
return 0;
}
/**
* tx_cmd_set_sigs() - Sends the signal set command
* @if_ptr: Pointer to interface instance
* @lcid: Local channel ID
* @sigs: New signals
*
* Return: 0 on success, standard error codes otherwise
*/
static int tx_cmd_set_sigs(struct glink_transport_if *if_ptr, uint32_t lcid,
uint32_t sigs)
{
struct glink_loopback_xprt *loopback_xprt_ptr =
(struct glink_loopback_xprt *)if_ptr;
struct glink_loopback_xprt_cmd *cmd =
kzalloc(sizeof(struct glink_loopback_xprt_cmd), GFP_KERNEL);
if (!cmd) {
GLX_ERR("%s: No memory for allocation\n", __func__);
return -ENOMEM;
}
GLX_INFO_PERF("lcid: %d, %s: start SIGS_SET\n", lcid, __func__);
cmd->type = SIGS_SET;
cmd->sigs_set.lcid = lcid;
cmd->sigs_set.sigs = sigs;
mutex_lock(&loopback_xprt_ptr->tx_cmds_lock);
simulate_smem_loopback((void *)cmd, sizeof(*cmd));
list_add_tail(&cmd->element, &loopback_xprt_ptr->tx_cmds);
mutex_unlock(&loopback_xprt_ptr->tx_cmds_lock);
queue_work(loopback_xprt_ptr->ll_wq, &loopback_xprt_ptr->ll_cmd_work);
GLX_INFO_PERF("lcid: %d, %s: finish SIGS_SET\n", lcid, __func__);
return 0;
}
/**
* init_loopback_xprt_lists() - Initialize loopback transport lists
*
* Return: 0
*/
static int init_loopback_xprt_lists(void)
{
mutex_init(&loopback_xprt.ch_map_lock);
mutex_init(&loopback_xprt.tx_cmds_lock);
INIT_LIST_HEAD(&loopback_xprt.ch_map);
INIT_LIST_HEAD(&loopback_xprt.tx_cmds);
return 0;
}
static void deinit_loopback_xprt_lists(void)
{
struct ch_map_info *temp_map, *temp_map1;
struct glink_loopback_xprt_cmd *temp_cmd, *temp_cmd1;
mutex_lock(&loopback_xprt.ch_map_lock);
list_for_each_entry_safe(temp_map, temp_map1,
&loopback_xprt.ch_map, list) {
list_del(&temp_map->list);
kfree(temp_map);
}
mutex_unlock(&loopback_xprt.ch_map_lock);
mutex_lock(&loopback_xprt.tx_cmds_lock);
list_for_each_entry_safe(temp_cmd, temp_cmd1,
&loopback_xprt.tx_cmds, element) {
list_del(&temp_cmd->element);
kfree(temp_cmd);
}
mutex_unlock(&loopback_xprt.tx_cmds_lock);
}
/**
* init_loopback_xprt_works() - Initialize the loopback transport workqueue
*
* Return: 0 on success, standard error codes otherwise
*/
static int init_loopback_xprt_works(void)
{
loopback_xprt.ll_wq =
create_singlethread_workqueue("glink_loopback_xprt");
if (!loopback_xprt.ll_wq)
return -ENOMEM;
INIT_WORK(&loopback_xprt.ll_cmd_work, ll_cmd_worker);
return 0;
}
/**
* init_loopback_xprt_works() - Flush and destroy the loopback transport
* workqueue
*/
static void deinit_loopback_xprt_works(void)
{
flush_workqueue(loopback_xprt.ll_wq);
destroy_workqueue(loopback_xprt.ll_wq);
loopback_xprt.ll_wq = NULL;
}
void glink_loopback_xprt_link_up(void)
{
loopback_xprt.if_ptr.glink_core_if_ptr->link_up(&loopback_xprt.if_ptr);
}
/* init_and_register_loopback_xprt_if() - Initialize the loopback transport
* and register it with the G-Link core
*
* Return: 0 on success, standard error codes otherwise
*/
static int init_and_register_loopback_xprt_if(void)
{
struct glink_core_transport_cfg cfg;
int ret;
memset(&cfg, 0, sizeof(cfg));
loopback_xprt.if_ptr.ssr = ssr;
loopback_xprt.if_ptr.tx_cmd_version = tx_cmd_version;
loopback_xprt.if_ptr.tx_cmd_version_ack = tx_cmd_version_ack;
loopback_xprt.if_ptr.set_version = set_version;
loopback_xprt.if_ptr.tx_cmd_ch_open = tx_cmd_ch_open;
loopback_xprt.if_ptr.tx_cmd_ch_close = tx_cmd_ch_close;
loopback_xprt.if_ptr.tx_cmd_ch_remote_open_ack =
tx_cmd_ch_remote_open_ack;
loopback_xprt.if_ptr.tx_cmd_ch_remote_close_ack =
tx_cmd_ch_remote_close_ack;
loopback_xprt.if_ptr.allocate_rx_intent = allocate_rx_intent;
loopback_xprt.if_ptr.deallocate_rx_intent = deallocate_rx_intent;
loopback_xprt.if_ptr.reuse_rx_intent = reuse_rx_intent;
loopback_xprt.if_ptr.tx_cmd_local_rx_intent = tx_cmd_local_rx_intent;
loopback_xprt.if_ptr.tx_cmd_local_rx_done = tx_cmd_local_rx_done;
loopback_xprt.if_ptr.tx_cmd_rx_intent_req = tx_cmd_rx_intent_req;
loopback_xprt.if_ptr.tx_cmd_remote_rx_intent_req_ack =
tx_cmd_remote_rx_intent_req_ack;
loopback_xprt.if_ptr.tx_cmd_set_sigs = tx_cmd_set_sigs;
loopback_xprt.if_ptr.tx = tx;
loopback_xprt.if_ptr.tx_cmd_tracer_pkt = tx_cmd_tracer_pkt;
/* initialize transport */
loopback_xprt.if_ptr.glink_core_if_ptr = NULL;
cfg.name = "lloop";
cfg.edge = "local";
cfg.versions = versions;
cfg.versions_entries = ARRAY_SIZE(versions);
cfg.max_cid = UINT32_MAX;
cfg.max_iid = UINT32_MAX;
ret = glink_core_register_transport(&loopback_xprt.if_ptr, &cfg);
if (ret)
GLX_ERR("%s: Unable to register transport %d\n", __func__, ret);
else
glink_loopback_xprt_link_up();
return ret;
}
int glink_loopback_xprt_init(void)
{
int ret;
ret = init_loopback_xprt_lists();
if (ret < 0) {
GLX_ERR("%s: Error initializing lists\n", __func__);
return ret;
}
ret = init_loopback_xprt_works();
if (ret < 0) {
GLX_ERR("%s: Error initializing works\n", __func__);
return ret;
}
ret = init_and_register_loopback_xprt_if();
if (ret < 0) {
deinit_loopback_xprt_works();
GLX_ERR("%s: Error registering xprt\n", __func__);
}
GLX_INFO("%s: Complete\n", __func__);
return ret;
}
void glink_loopback_xprt_exit(void)
{
loopback_xprt.if_ptr.glink_core_if_ptr->link_down(&loopback_xprt.if_ptr);
deinit_loopback_xprt_works();
deinit_loopback_xprt_lists();
glink_core_unregister_transport(&loopback_xprt.if_ptr);
}