6493564fe3
Neuron is a device-sharing framework which is used by guests of the haven hypervisor to serve or access shared I/O devices and other inter-VM services. There are three main layers that make up a neuron service. channel - the physical layer transport that uses the hypervisor provided transports. protocol - defines the syntax and semantics to virtualize a specific device across VMs. Block and Net are examples of protocols. application - integrates the neuron service components into the rest of the system. There would be front and back end application drivers for the net protocol. Change-Id: Ic7278fdaee1cd30147e91e1126643bce79c05e52 Signed-off-by: Chris Lew <clew@codeaurora.org>
205 lines
4.8 KiB
C
205 lines
4.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/* Copyright (c) 2020 The Linux Foundation. All rights reserved. */
|
|
|
|
/* Neuron service driver
|
|
*
|
|
* This driver parses DT description of a Neuron service and creates protocol,
|
|
* application, and channel devices based on the DT nodes.
|
|
*/
|
|
#include <linux/init.h>
|
|
#include <linux/err.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/version.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/of.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "neuron_service.h"
|
|
|
|
#define DRIVER_NAME "neuron-service"
|
|
#define DEVICE_NAME "neuron-service"
|
|
|
|
#ifndef CONFIG_OF
|
|
#error "neuron service driver only supported on device tree kernels"
|
|
#endif
|
|
|
|
static const struct of_device_id neuron_service_match[] = {
|
|
{
|
|
.compatible = "qcom,neuron-service",
|
|
},
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, neuron_service_match);
|
|
|
|
static int neuron_service_probe(struct platform_device *pdev)
|
|
{
|
|
struct neuron_service *neuron_serv;
|
|
static struct device_node *node;
|
|
static struct device_node *pnode;
|
|
int count = 0;
|
|
int err;
|
|
int i = 0;
|
|
|
|
node = NULL;
|
|
pnode = pdev->dev.of_node;
|
|
|
|
for_each_child_of_node(pnode, node)
|
|
if (node->name && (of_node_cmp(node->name, "channel") == 0))
|
|
count++;
|
|
|
|
if (!count) {
|
|
err = -ENODEV;
|
|
goto fail_find_channels;
|
|
}
|
|
|
|
neuron_serv = kzalloc(sizeof(*neuron_serv) +
|
|
sizeof(struct neuron_channel *) * count,
|
|
GFP_KERNEL);
|
|
if (!neuron_serv) {
|
|
err = -ENOMEM;
|
|
goto fail_alloc_neuron_serv;
|
|
}
|
|
|
|
neuron_serv->channel_count = count;
|
|
node = NULL;
|
|
|
|
for_each_child_of_node(pnode, node) {
|
|
if (node->name && (of_node_cmp(node->name, "channel") == 0)) {
|
|
neuron_serv->channels[i] =
|
|
neuron_channel_add(node, &pdev->dev);
|
|
if (IS_ERR(neuron_serv->channels[i])) {
|
|
err = PTR_ERR(neuron_serv->channels[i]);
|
|
goto fail_add_channel;
|
|
}
|
|
neuron_serv->channels[i]->id = i;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
node = of_get_child_by_name(pnode, "application");
|
|
if (!node) {
|
|
err = -ENODEV;
|
|
goto fail_find_application;
|
|
}
|
|
|
|
neuron_serv->application =
|
|
neuron_app_add(node, &pdev->dev);
|
|
|
|
if (IS_ERR(neuron_serv->application)) {
|
|
err = PTR_ERR(neuron_serv->application);
|
|
goto fail_add_application;
|
|
}
|
|
|
|
node = of_get_child_by_name(pnode, "protocol");
|
|
if (!node) {
|
|
err = -ENODEV;
|
|
goto fail_find_protocol;
|
|
}
|
|
|
|
neuron_serv->protocol =
|
|
neuron_protocol_add(node, count, neuron_serv->channels,
|
|
&pdev->dev, neuron_serv->application);
|
|
if (IS_ERR(neuron_serv->protocol)) {
|
|
err = PTR_ERR(neuron_serv->protocol);
|
|
goto fail_add_protocol;
|
|
}
|
|
|
|
for (i = 0; i < neuron_serv->channel_count; i++) {
|
|
neuron_serv->channels[i]->protocol = neuron_serv->protocol;
|
|
get_device(&neuron_serv->protocol->dev);
|
|
}
|
|
|
|
/* Save protocol pointer */
|
|
neuron_serv->application->protocol = neuron_serv->protocol;
|
|
get_device(&neuron_serv->protocol->dev);
|
|
|
|
dev_set_drvdata(&pdev->dev, neuron_serv);
|
|
|
|
return 0;
|
|
|
|
fail_add_application:
|
|
fail_find_application:
|
|
device_unregister(&neuron_serv->protocol->dev);
|
|
put_device(&neuron_serv->protocol->dev);
|
|
fail_add_protocol:
|
|
fail_find_protocol:
|
|
for (i = 0; i < (neuron_serv->channel_count); i++) {
|
|
device_unregister(&neuron_serv->channels[i]->dev);
|
|
put_device(&neuron_serv->channels[i]->dev);
|
|
}
|
|
fail_add_channel:
|
|
dev_set_drvdata(&pdev->dev, NULL);
|
|
kfree(neuron_serv);
|
|
fail_alloc_neuron_serv:
|
|
fail_find_channels:
|
|
return err;
|
|
}
|
|
|
|
static int neuron_service_remove(struct platform_device *pdev)
|
|
{
|
|
struct neuron_service *neuron_serv;
|
|
int i;
|
|
|
|
neuron_serv = dev_get_drvdata(&pdev->dev);
|
|
|
|
/* Clearing all pointers to devices */
|
|
neuron_serv->application->protocol = NULL;
|
|
neuron_serv->protocol->application = NULL;
|
|
for (i = 0; i < (neuron_serv->channel_count); i++) {
|
|
neuron_serv->protocol->channels[i] = NULL;
|
|
neuron_serv->channels[i]->protocol = NULL;
|
|
}
|
|
|
|
device_unregister(&neuron_serv->application->dev);
|
|
put_device(&neuron_serv->application->dev);
|
|
|
|
device_unregister(&neuron_serv->protocol->dev);
|
|
put_device(&neuron_serv->protocol->dev);
|
|
|
|
for (i = 0; i < (neuron_serv->channel_count); i++) {
|
|
device_unregister(&neuron_serv->channels[i]->dev);
|
|
put_device(&neuron_serv->channels[i]->dev);
|
|
}
|
|
|
|
dev_set_drvdata(&pdev->dev, NULL);
|
|
kfree(neuron_serv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver neuron_service_driver = {
|
|
.driver = {
|
|
.name = DRIVER_NAME,
|
|
.of_match_table = neuron_service_match,
|
|
},
|
|
.probe = neuron_service_probe,
|
|
.remove = neuron_service_remove,
|
|
};
|
|
|
|
static int __init neuron_service_init(void)
|
|
{
|
|
int ret;
|
|
|
|
ret = platform_driver_register(&neuron_service_driver);
|
|
if (ret < 0) {
|
|
pr_err("Failed to register driver\n");
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __exit neuron_service_exit(void)
|
|
{
|
|
platform_driver_unregister(&neuron_service_driver);
|
|
}
|
|
|
|
module_init(neuron_service_init);
|
|
module_exit(neuron_service_exit);
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_DESCRIPTION("Neuron service - configuration layer");
|