mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 09:11:26 +03:00
fsicom: add fsicom multi core support
- smmu and hsp support added for fsicom multi core feature in fsicom kernel driver - probe, suspend and resume will be called for smmu_inst 0 only as it will have single dev node for comm. - mailbox 2,5 and 1,4 is used for TX and RX comm. respectively with FSI Jira SS-5744 Change-Id: I859d5945853195ba76996a8c36ca19efd9c4409f Signed-off-by: pshaw <pshaw@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2952268 Reviewed-by: Praveen James <pjames@nvidia.com> Reviewed-by: Sumeet Gupta <sumeetg@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
@@ -40,25 +40,32 @@ struct fsi_hsp {
|
||||
struct device dev;
|
||||
};
|
||||
|
||||
struct fsi_dev_ctx {
|
||||
struct platform_device *pdev;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static int device_file_major_number;
|
||||
static const char device_name[] = "fsicom-client";
|
||||
|
||||
static struct platform_device *pdev_local;
|
||||
static struct dma_buf_attachment *attach;
|
||||
static struct sg_table *sgt;
|
||||
static struct dma_buf *dmabuf;
|
||||
|
||||
/* Signaling to Application */
|
||||
static struct task_struct *task;
|
||||
|
||||
static struct fsi_hsp *fsi_hsp_v;
|
||||
static struct fsi_hsp *fsi_hsp_v[MAX_FSI_CORE];
|
||||
|
||||
static bool enable_deinit_notify;
|
||||
|
||||
static int sgMaxCore;
|
||||
|
||||
static LIST_HEAD(fsi_dev_list);
|
||||
static DEFINE_MUTEX(fsi_dev_list_mutex);
|
||||
|
||||
static int fsicom_fsi_pm_notify(u32 state)
|
||||
{
|
||||
uint32_t pdata[4] = {0};
|
||||
int ret = 0;
|
||||
int8_t lCoreId;
|
||||
|
||||
pdata[0] = state;
|
||||
pdata[1] = state;
|
||||
@@ -66,8 +73,10 @@ static int fsicom_fsi_pm_notify(u32 state)
|
||||
pdata[3] = PM_STATE_UNI_CODE;
|
||||
|
||||
/* send pm state to fsi */
|
||||
ret = mbox_send_message(fsi_hsp_v->tx.chan,
|
||||
for (lCoreId = sgMaxCore - 1; lCoreId >= 0; lCoreId--) {
|
||||
ret = mbox_send_message(fsi_hsp_v[lCoreId]->tx.chan,
|
||||
(void *)pdata);
|
||||
}
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
@@ -101,73 +110,93 @@ static void tegra_hsp_tx_empty_notify(struct mbox_client *cl,
|
||||
static int tegra_hsp_mb_init(struct device *dev)
|
||||
{
|
||||
int err;
|
||||
uint8_t lCoreId;
|
||||
char lTxStr[100] = {0};
|
||||
char lRxStr[100] = {0};
|
||||
|
||||
fsi_hsp_v = devm_kzalloc(dev, sizeof(*fsi_hsp_v), GFP_KERNEL);
|
||||
if (!fsi_hsp_v)
|
||||
for (lCoreId = 0; lCoreId < sgMaxCore; lCoreId++) {
|
||||
fsi_hsp_v[lCoreId] = devm_kzalloc(dev, sizeof(*fsi_hsp_v[lCoreId]), GFP_KERNEL);
|
||||
if (!fsi_hsp_v[lCoreId])
|
||||
return -ENOMEM;
|
||||
|
||||
if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)))
|
||||
dev_err(dev, "FsiCom: setting DMA MASK failed!\n");
|
||||
|
||||
fsi_hsp_v->tx.client.dev = dev;
|
||||
fsi_hsp_v->rx.client.dev = dev;
|
||||
fsi_hsp_v->tx.client.tx_block = true;
|
||||
fsi_hsp_v->tx.client.tx_tout = TIMEOUT;
|
||||
fsi_hsp_v->rx.client.rx_callback = tegra_hsp_rx_notify;
|
||||
fsi_hsp_v->tx.client.tx_done = tegra_hsp_tx_empty_notify;
|
||||
fsi_hsp_v[lCoreId]->tx.client.dev = dev;
|
||||
fsi_hsp_v[lCoreId]->rx.client.dev = dev;
|
||||
fsi_hsp_v[lCoreId]->tx.client.tx_block = true;
|
||||
fsi_hsp_v[lCoreId]->tx.client.tx_tout = TIMEOUT;
|
||||
fsi_hsp_v[lCoreId]->rx.client.rx_callback = tegra_hsp_rx_notify;
|
||||
fsi_hsp_v[lCoreId]->tx.client.tx_done = tegra_hsp_tx_empty_notify;
|
||||
|
||||
fsi_hsp_v->tx.chan = mbox_request_channel_byname(&fsi_hsp_v->tx.client,
|
||||
"fsi-tx");
|
||||
if (IS_ERR(fsi_hsp_v->tx.chan)) {
|
||||
err = PTR_ERR(fsi_hsp_v->tx.chan);
|
||||
snprintf(lTxStr, sizeof(lTxStr), "fsi-tx-cpu%d", lCoreId);
|
||||
fsi_hsp_v[lCoreId]->tx.chan = mbox_request_channel_byname(
|
||||
&fsi_hsp_v[lCoreId]->tx.client,
|
||||
lTxStr);
|
||||
if (IS_ERR(fsi_hsp_v[lCoreId]->tx.chan)) {
|
||||
err = PTR_ERR(fsi_hsp_v[lCoreId]->tx.chan);
|
||||
dev_err(dev, "failed to get tx mailbox: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
fsi_hsp_v->rx.chan = mbox_request_channel_byname(&fsi_hsp_v->rx.client,
|
||||
"fsi-rx");
|
||||
if (IS_ERR(fsi_hsp_v->rx.chan)) {
|
||||
err = PTR_ERR(fsi_hsp_v->rx.chan);
|
||||
snprintf(lRxStr, sizeof(lRxStr), "fsi-rx-cpu%d", lCoreId);
|
||||
fsi_hsp_v[lCoreId]->rx.chan = mbox_request_channel_byname(
|
||||
&fsi_hsp_v[lCoreId]->rx.client,
|
||||
lRxStr);
|
||||
if (IS_ERR(fsi_hsp_v[lCoreId]->rx.chan)) {
|
||||
err = PTR_ERR(fsi_hsp_v[lCoreId]->rx.chan);
|
||||
dev_err(dev, "failed to get rx mailbox: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t device_file_ioctl(
|
||||
struct file *fp, unsigned int cmd, unsigned long arg)
|
||||
static int smmu_buff_map(unsigned long arg)
|
||||
{
|
||||
struct rw_data input;
|
||||
u32 val;
|
||||
int ret;
|
||||
dma_addr_t dma_addr;
|
||||
dma_addr_t phys_addr;
|
||||
struct rw_data input;
|
||||
struct rw_data *user_input;
|
||||
int ret = 0;
|
||||
uint32_t pdata[4] = {0};
|
||||
struct iova_data ldata;
|
||||
struct fsi_dev_ctx *ctx = NULL;
|
||||
struct dma_buf_attachment *attach;
|
||||
struct sg_table *sgt;
|
||||
struct dma_buf *dmabuf;
|
||||
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case NVMAP_SMMU_MAP:
|
||||
user_input = (struct rw_data *)arg;
|
||||
if (copy_from_user(&input, (void __user *)arg,
|
||||
sizeof(struct rw_data)))
|
||||
return -EACCES;
|
||||
|
||||
list_for_each_entry(ctx, &fsi_dev_list, list) {
|
||||
if ((ctx != NULL) && (ctx->pdev != NULL)) {
|
||||
ret = of_property_read_u32(ctx->pdev->dev.of_node, "smmu_inst", &val);
|
||||
if (ret) {
|
||||
pr_err("failed to read smmu_inst\n");
|
||||
return -1;
|
||||
}
|
||||
if (val == input.coreid)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (val == input.coreid) {
|
||||
dmabuf = dma_buf_get(input.handle);
|
||||
|
||||
if (IS_ERR_OR_NULL(dmabuf))
|
||||
return -EINVAL;
|
||||
attach = dma_buf_attach(dmabuf, &pdev_local->dev);
|
||||
return PTR_ERR(dmabuf);
|
||||
attach = dma_buf_attach(dmabuf, &ctx->pdev->dev);
|
||||
|
||||
if (IS_ERR_OR_NULL(attach)) {
|
||||
pr_err("error : %lld\n", (signed long long)attach);
|
||||
return -1;
|
||||
return PTR_ERR(attach);
|
||||
}
|
||||
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR_OR_NULL(sgt)) {
|
||||
pr_err("error: %lld\n", (signed long long)sgt);
|
||||
return -1;
|
||||
return PTR_ERR(sgt);
|
||||
}
|
||||
phys_addr = sg_phys(sgt->sgl);
|
||||
dma_addr = sg_dma_address(sgt->sgl);
|
||||
@@ -186,7 +215,24 @@ static ssize_t device_file_ioctl(
|
||||
if (copy_to_user((void __user *)&user_input->sgt,
|
||||
(void *)&sgt, sizeof(uint64_t)))
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t device_file_ioctl(
|
||||
struct file *fp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct rw_data input;
|
||||
int ret = 0;
|
||||
uint32_t pdata[4] = {0};
|
||||
struct iova_data ldata;
|
||||
struct rw_data *user_input;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case NVMAP_SMMU_MAP:
|
||||
ret = smmu_buff_map(arg);
|
||||
break;
|
||||
|
||||
case NVMAP_SMMU_UNMAP:
|
||||
@@ -205,12 +251,16 @@ static ssize_t device_file_ioctl(
|
||||
sizeof(struct rw_data)))
|
||||
return -EACCES;
|
||||
pdata[0] = input.handle;
|
||||
ret = mbox_send_message(fsi_hsp_v->tx.chan,
|
||||
ret = mbox_send_message(fsi_hsp_v[input.coreid]->tx.chan,
|
||||
(void *)pdata);
|
||||
break;
|
||||
|
||||
case TEGRA_SIGNAL_REG:
|
||||
task = get_current();
|
||||
user_input = (struct rw_data *)arg;
|
||||
if (copy_to_user((void __user *)&user_input->coreid,
|
||||
(void *)&sgMaxCore, sizeof(uint8_t)))
|
||||
return -EACCES;
|
||||
break;
|
||||
|
||||
case TEGRA_IOVA_DATA:
|
||||
@@ -221,14 +271,13 @@ static ssize_t device_file_ioctl(
|
||||
pdata[1] = ldata.iova;
|
||||
pdata[2] = ldata.chid;
|
||||
pdata[3] = IOVA_UNI_CODE;
|
||||
ret = mbox_send_message(fsi_hsp_v->tx.chan,
|
||||
ret = mbox_send_message(fsi_hsp_v[ldata.coreid]->tx.chan,
|
||||
(void *)pdata);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -286,49 +335,119 @@ MODULE_DEVICE_TABLE(of, fsicom_client_dt_match);
|
||||
static int fsicom_client_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 val;
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct device_node *np = dev->of_node;
|
||||
struct fsi_dev_ctx *ctx;
|
||||
|
||||
ret = of_property_read_u32(np, "smmu_inst", &val);
|
||||
if (ret) {
|
||||
pr_err("failed to read smmu_inst\n");
|
||||
return -1;
|
||||
}
|
||||
if (val == 0) {
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "max_fsi_core", &sgMaxCore);
|
||||
if (ret) {
|
||||
pr_err("failed to read smmu_inst\n");
|
||||
return -1;
|
||||
}
|
||||
if (sgMaxCore > MAX_FSI_CORE)
|
||||
return -1;
|
||||
fsicom_register_device();
|
||||
ret = tegra_hsp_mb_init(&pdev->dev);
|
||||
pdev_local = pdev;
|
||||
|
||||
if (of_property_read_bool(np, "enable-deinit-notify"))
|
||||
enable_deinit_notify = true;
|
||||
}
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
INIT_LIST_HEAD(&ctx->list);
|
||||
ctx->pdev = pdev;
|
||||
|
||||
mutex_lock(&fsi_dev_list_mutex);
|
||||
list_add_tail(&ctx->list, &fsi_dev_list);
|
||||
mutex_unlock(&fsi_dev_list_mutex);
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fsicom_client_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "smmu_inst", &val);
|
||||
if (ret) {
|
||||
pr_err("failed to read smmu_inst\n");
|
||||
return;
|
||||
}
|
||||
if (val == 0) {
|
||||
if (enable_deinit_notify)
|
||||
if (fsicom_fsi_pm_notify(PM_SHUTDOWN) < 0)
|
||||
pr_err("Unable to send notification to fsi\n");
|
||||
|
||||
fsicom_unregister_device();
|
||||
}
|
||||
}
|
||||
|
||||
static int fsicom_client_remove(struct platform_device *pdev)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
struct fsi_dev_ctx *ctx = platform_get_drvdata(pdev);
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "smmu_inst", &val);
|
||||
if (ret) {
|
||||
pr_err("failed to read smmu_inst\n");
|
||||
return -1;
|
||||
}
|
||||
if (val == 0) {
|
||||
pr_debug("fsicom remove called");
|
||||
fsicom_unregister_device();
|
||||
mutex_lock(&fsi_dev_list_mutex);
|
||||
list_del(&ctx->list);
|
||||
mutex_unlock(&fsi_dev_list_mutex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused fsicom_client_suspend(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
dev_dbg(dev, "suspend called\n");
|
||||
ret = of_property_read_u32(dev->of_node, "smmu_inst", &val);
|
||||
if (ret) {
|
||||
pr_err("failed to read smmu_inst\n");
|
||||
return -1;
|
||||
}
|
||||
if (val == 0) {
|
||||
if (enable_deinit_notify)
|
||||
ret = fsicom_fsi_pm_notify(PM_SUSPEND);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused fsicom_client_resume(struct device *dev)
|
||||
{
|
||||
dev_dbg(dev, "resume called\n");
|
||||
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
dev_dbg(dev, "resume called\n");
|
||||
ret = of_property_read_u32(dev->of_node, "smmu_inst", &val);
|
||||
if (ret) {
|
||||
pr_err("failed to read smmu_inst\n");
|
||||
return -1;
|
||||
}
|
||||
if (val == 0)
|
||||
fsicom_send_signal(SIG_DRIVER_RESUME, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#define MAX_FSI_CORE 2
|
||||
|
||||
struct rw_data {
|
||||
uint8_t coreid;
|
||||
uint32_t handle;
|
||||
uint64_t pa;
|
||||
uint64_t iova;
|
||||
@@ -19,6 +22,7 @@ struct rw_data {
|
||||
|
||||
/*Data type for sending the offset,IOVA and channel Id details to FSI */
|
||||
struct iova_data {
|
||||
uint8_t coreid;
|
||||
uint32_t offset;
|
||||
uint32_t iova;
|
||||
uint32_t chid;
|
||||
|
||||
Reference in New Issue
Block a user