174 lines
4.7 KiB
C
Executable File
174 lines
4.7 KiB
C
Executable File
/*
|
|
* Copyright (C) 2018-2019 Unisoc Corporation
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* 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/device.h>
|
|
#include <linux/init.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/io.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/completion.h>
|
|
|
|
#include "../include/sipa.h"
|
|
#include "../include/sipc.h"
|
|
#include "../include/sprd_pcie_ep_device.h"
|
|
#include "sipa_core.h"
|
|
|
|
#define SIPA_PCIE_DL_CMN_FIFO_REG_OFFSET 0x980
|
|
#define SIPA_PCIE_UL_CMN_FIFO_REG_OFFSET 0x200
|
|
|
|
#ifndef devm_ioremap_nocache
|
|
#define devm_ioremap_nocache devm_ioremap
|
|
#endif
|
|
|
|
static int sipa_dele_start_req_work(void)
|
|
{
|
|
struct smsg msg;
|
|
|
|
msg.channel = SMSG_CH_COMM_SIPA;
|
|
msg.type = SMSG_TYPE_CMD;
|
|
msg.flag = SMSG_FLG_DELE_REQUEST;
|
|
msg.value = 0;
|
|
|
|
return smsg_send(SIPC_ID_MINIAP, &msg, -1);
|
|
}
|
|
|
|
static int sipa_init_tft_cmn_fifo_reg_addr(struct sipa_core *ipa)
|
|
{
|
|
ipa->tft_reg_mapped = sprd_ep_ipa_map(PCIE_IPA_TYPE_TFT_REG,
|
|
ipa->tft_res->start, resource_size(ipa->tft_res));
|
|
ipa->tft_virt_reg_addr = devm_ioremap_nocache(ipa->dev,
|
|
(resource_size_t)ipa->tft_reg_mapped,
|
|
(resource_size_t)(resource_size(ipa->tft_res)));
|
|
if (!ipa->tft_virt_reg_addr) {
|
|
dev_err(ipa->dev, "ipa tft reg base remap fail\n");
|
|
return -ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int sipa_init_cmn_fifo_reg_addr(struct sipa_core *ipa)
|
|
{
|
|
ipa->reg_mapped = sprd_ep_ipa_map(PCIE_IPA_TYPE_REG,
|
|
ipa->reg_res->start,
|
|
resource_size(ipa->reg_res));
|
|
ipa->virt_reg_addr = devm_ioremap_nocache(ipa->dev,
|
|
(resource_size_t)ipa->reg_mapped,
|
|
(resource_size_t)(resource_size(ipa->reg_res)));
|
|
if (!ipa->virt_reg_addr) {
|
|
dev_err(ipa->dev, "ipa reg base remap fail\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ipa->cmn_fifo_cfg[SIPA_FIFO_PCIE_DL].fifo_reg_base =
|
|
ipa->virt_reg_addr + SIPA_PCIE_DL_CMN_FIFO_REG_OFFSET;
|
|
ipa->cmn_fifo_cfg[SIPA_FIFO_PCIE_UL].fifo_reg_base =
|
|
ipa->virt_reg_addr + SIPA_PCIE_UL_CMN_FIFO_REG_OFFSET;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int conn_thread(void *data)
|
|
{
|
|
struct smsg mrecv;
|
|
int ret, timeout = 500;
|
|
struct sipa_core *ipa = data;
|
|
|
|
/* since the channel open may hang, we call it in the thread context */
|
|
usleep_range(100000, 200000);
|
|
ret = smsg_ch_open(SIPC_ID_MINIAP, SMSG_CH_COMM_SIPA, -1);
|
|
if (ret != 0) {
|
|
dev_err(ipa->dev, "sipa_delegator failed to open dst %d channel %d\n",
|
|
SIPC_ID_MINIAP, SMSG_CH_COMM_SIPA);
|
|
/* assign NULL to thread poniter as failed to open channel */
|
|
return ret;
|
|
}
|
|
|
|
while (sipa_dele_start_req_work() && timeout--)
|
|
usleep_range(5000, 10000);
|
|
|
|
/* start listen the smsg events */
|
|
while (!kthread_should_stop()) {
|
|
/* monitor seblock recv smsg */
|
|
smsg_set(&mrecv, SMSG_CH_COMM_SIPA, 0, 0, 0);
|
|
ret = smsg_recv(SIPC_ID_MINIAP, &mrecv, -1);
|
|
if (ret == -EIO || ret == -ENODEV) {
|
|
/* channel state is FREE */
|
|
usleep_range(5000, 10000);
|
|
continue;
|
|
}
|
|
|
|
dev_dbg(ipa->dev, "sipa type=%d, flag=0x%x, value=0x%08x\n",
|
|
mrecv.type, mrecv.flag, mrecv.value);
|
|
|
|
switch (mrecv.type) {
|
|
case SMSG_TYPE_OPEN:
|
|
/* just ack open */
|
|
smsg_open_ack(SIPC_ID_AP, SMSG_CH_COMM_SIPA);
|
|
break;
|
|
case SMSG_TYPE_CLOSE:
|
|
/* handle channel close */
|
|
smsg_close_ack(SIPC_ID_AP, SMSG_CH_COMM_SIPA);
|
|
break;
|
|
case SMSG_TYPE_CMD:
|
|
/* handle commads */
|
|
break;
|
|
case SMSG_TYPE_DONE:
|
|
sipa_init_cmn_fifo_reg_addr(ipa);
|
|
sipa_init_tft_cmn_fifo_reg_addr(ipa);
|
|
dev_info(ipa->dev, "remote ipa ready reg_mapped = 0x%llx\n", (long long unsigned int)ipa->reg_mapped);
|
|
sipa_receiver_open_cmn_fifo(ipa->receiver);
|
|
sipa_sender_open_cmn_fifo(ipa->sender);
|
|
sipa_nic_check_flow_ctrl();
|
|
ipa->remote_ready = true;
|
|
/* handle cmd done */
|
|
break;
|
|
case SMSG_TYPE_EVENT:
|
|
/* handle events */
|
|
break;
|
|
default:
|
|
ret = 1;
|
|
break;
|
|
};
|
|
|
|
if (ret) {
|
|
dev_info(ipa->dev, "unknown msg in conn_thrd: %d, %d, %d\n",
|
|
mrecv.type, mrecv.flag, mrecv.value);
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sipa_create_smsg_channel(struct sipa_core *ipa)
|
|
{
|
|
/* create channel thread for this seblock channel */
|
|
ipa->smsg_thread = kthread_create(conn_thread, ipa, "sipa-dele");
|
|
if (IS_ERR(ipa->smsg_thread)) {
|
|
dev_err(ipa->dev, "Failed to create monitor smsg kthread\n");
|
|
return PTR_ERR(ipa->smsg_thread);
|
|
}
|
|
|
|
wake_up_process(ipa->smsg_thread);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(sipa_create_smsg_channel);
|