Commit 2d934649 authored by Yizhen Fan's avatar Yizhen Fan Committed by fanyizhen1995
Browse files

ub: Add register device api in ubcore



driver inclusion
category: feature
bugzilla: NA
CVE: NA

--------------------------------

Add register device api in ubcore.

This interface is invoked during UBN driver loading and initialization
to register the UB device with the UB Core protocol layer.

Input parameter:
dev: The structure contains netdev, device name, ops,
and vendor-defined device private data.
Device names of different functions of the same vendor must be unique.
Deduplicated by the protocol stack.
The memory of ubcore_device_t is allocated by the UBN driver.

Return value:
The value 0 indicates that the registration is successful.
Other values indicate that the registration fails.

Signed-off-by: default avatarGuoxin Qian <qianguoxin@huawei.com>
Signed-off-by: default avatarYizhen Fan <fanyizhen@huawei.com>
parent 45dde1be
Loading
Loading
Loading
Loading
+189 −1
Original line number Diff line number Diff line
@@ -28,8 +28,9 @@
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>

#include <urma/ubcore_uapi.h>
#include "ubcore_log.h"
#include <urma/ubcore_uapi.h>
#include <urma/ubcore_api.h>
#include "ubcore_priv.h"

static LIST_HEAD(g_client_list);
@@ -45,6 +46,43 @@ static LIST_HEAD(g_device_list);
static DEFINE_MUTEX(g_device_mutex);
static DECLARE_RWSEM(g_lists_rwsem);

static struct ubcore_client_ctx *create_client_ctx(struct ubcore_device *dev,
						   struct ubcore_client *client)
{
	struct ubcore_client_ctx *ctx;
	unsigned long flags;

	ctx = kmalloc(sizeof(struct ubcore_client_ctx), GFP_KERNEL);
	if (!ctx)
		return NULL;

	ctx->data = NULL;
	ctx->client = client;

	down_write(&g_lists_rwsem);
	spin_lock_irqsave(&dev->client_ctx_lock, flags);
	list_add(&ctx->list_node, &dev->client_ctx_list);
	spin_unlock_irqrestore(&dev->client_ctx_lock, flags);
	up_write(&g_lists_rwsem);

	return ctx;
}

static void destroy_client_ctx(struct ubcore_device *dev, struct ubcore_client_ctx *ctx)
{
	unsigned long flags;

	if (dev == NULL || ctx == NULL)
		return;

	down_write(&g_lists_rwsem);
	spin_lock_irqsave(&dev->client_ctx_lock, flags);
	list_del(&ctx->list_node);
	spin_unlock_irqrestore(&dev->client_ctx_lock, flags);
	up_write(&g_lists_rwsem);
	kfree(ctx);
}

struct ubcore_device *ubcore_find_device(union ubcore_eid *eid, enum ubcore_transport_type type)
{
	struct ubcore_device *dev, *target = NULL;
@@ -62,6 +100,22 @@ struct ubcore_device *ubcore_find_device(union ubcore_eid *eid, enum ubcore_tran
	return target;
}

/* Find only, without get_device */
static struct ubcore_device *ubcore_find_device_with_name(const char *dev_name)
{
	struct ubcore_device *dev, *target = NULL;

	mutex_lock(&g_device_mutex);
	list_for_each_entry(dev, &g_device_list, list_node) {
		if (strcmp(dev->dev_name, dev_name) == 0) {
			target = dev;
			break;
		}
	}
	mutex_unlock(&g_device_mutex);
	return target;
}

struct ubcore_device **ubcore_get_devices_from_netdev(struct net_device *netdev, uint32_t *cnt)
{
	struct ubcore_device **devices;
@@ -135,6 +189,122 @@ void ubcore_put_device(struct ubcore_device *dev)
		complete(&dev->comp);
}

static void ubcore_device_release(struct device *device)
{
}

static int init_ubcore_device(struct ubcore_device *dev)
{
	if (dev->ops->query_device_attr != NULL &&
	    dev->ops->query_device_attr(dev, &dev->attr) != 0) {
		ubcore_log_err("Failed to query device attributes");
		return -1;
	}

	device_initialize(&dev->dev);
	dev_set_drvdata(&dev->dev, dev);
	dev_set_name(&dev->dev, "%s", dev->dev_name);
	dev->dev.release = ubcore_device_release;

	INIT_LIST_HEAD(&dev->list_node);
	spin_lock_init(&dev->client_ctx_lock);
	INIT_LIST_HEAD(&dev->client_ctx_list);
	INIT_LIST_HEAD(&dev->port_list);
	spin_lock_init(&dev->event_handler_lock);
	INIT_LIST_HEAD(&dev->event_handler_list);

	init_completion(&dev->comp);
	atomic_set(&dev->use_cnt, 1);

	ubcore_set_default_eid(dev);
	return 0;
}

static void uninit_ubcore_device(struct ubcore_device *dev)
{
	put_device(&dev->dev);
}

int ubcore_register_device(struct ubcore_device *dev)
{
	struct ubcore_client *client = NULL;
	struct ubcore_client_ctx *ctx = NULL;

	if (dev == NULL || dev->ops == NULL || strlen(dev->dev_name) == 0) {
		ubcore_log_err("Invalid parameter.\n");
		return -EINVAL;
	}

	if (ubcore_find_device_with_name(dev->dev_name) != NULL) {
		ubcore_log_err("Duplicate device name %s.\n", dev->dev_name);
		return -EEXIST;
	}

	if (init_ubcore_device(dev) != 0) {
		ubcore_log_err("failed to init ubcore device.\n");
		return -EINVAL;
	}

	mutex_lock(&g_device_mutex);

	list_for_each_entry(client, &g_client_list, list_node) {
		ctx = create_client_ctx(dev, client);
		if (ctx == NULL)
			continue;
		if (client->add && client->add(dev) != 0) {
			destroy_client_ctx(dev, ctx);
			ubcore_log_err("ubcore device: %s register client:%s failed.\n",
				       dev->dev_name, client->client_name);
		}
	}

	down_write(&g_lists_rwsem);
	list_add_tail(&dev->list_node, &g_device_list);
	up_write(&g_lists_rwsem);

	mutex_unlock(&g_device_mutex);

	ubcore_log_info("ubcore device: %s register success.\n", dev->dev_name);
	return 0;
}
EXPORT_SYMBOL(ubcore_register_device);

void ubcore_unregister_device(struct ubcore_device *dev)
{
	struct ubcore_client_ctx *ctx, *tmp;

	mutex_lock(&g_device_mutex);

	/* Remove device from g_device_list */
	down_write(&g_lists_rwsem);
	list_del(&dev->list_node);

	/* Destroy uburma device, may be scheduled.
	 * This should not be done within a spin_lock_irqsave
	 */
	list_for_each_entry_safe(ctx, tmp, &dev->client_ctx_list, list_node) {
		if (ctx->client != NULL && ctx->client->remove != NULL)
			ctx->client->remove(dev, ctx->data);
	}
	up_write(&g_lists_rwsem);

	uninit_ubcore_device(dev);

	mutex_unlock(&g_device_mutex);

	/* Finally, free client ctx */
	list_for_each_entry_safe(ctx, tmp, &dev->client_ctx_list, list_node)
		destroy_client_ctx(dev, ctx);

	/* Pair with set use_cnt = 1 when init device */
	ubcore_put_device(dev);
	/* Wait for use cnt == 0 */
	wait_for_completion(&dev->comp);

	ubcore_log_info("ubcore device: %s unregister success.\n", dev->dev_name);
}
EXPORT_SYMBOL(ubcore_unregister_device);

int ubcore_set_eid(struct ubcore_device *dev, union ubcore_eid *eid)
{
	int ret;
@@ -154,6 +324,24 @@ int ubcore_set_eid(struct ubcore_device *dev, union ubcore_eid *eid)
}
EXPORT_SYMBOL(ubcore_set_eid);

int ubcore_query_device_attr(struct ubcore_device *dev, struct ubcore_device_attr *attr)
{
	int ret;

	if (dev == NULL || dev->ops == NULL || dev->ops->query_device_attr == NULL) {
		ubcore_log_err("Invalid argument.\n");
		return -EINVAL;
	}

	ret = dev->ops->query_device_attr(dev, attr);
	if (ret != 0) {
		ubcore_log_err("failed to query device attr, ret: %d.\n", ret);
		return -EPERM;
	}
	return 0;
}
EXPORT_SYMBOL(ubcore_query_device_attr);

int ubcore_query_stats(const struct ubcore_device *dev, struct ubcore_stats_key *key,
		       struct ubcore_stats_val *val)
{
+38 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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.
 *
 * Description: API definition provided by ubcore to ubep device driver
 * Author: Qian Guoxin
 * Create: 2022-1-25
 * Note:
 * History: 2022-1-25: Create file
 */

#ifndef UBCORE_API_H
#define UBCORE_API_H

#include <urma/ubcore_types.h>

/**
 * Register a device to ubcore
 * @param[in] dev: the ubcore device;
 * @return: 0 on success, other value on error
 */
int ubcore_register_device(struct ubcore_device *dev);
/**
 * Unregister a device from ubcore
 * @param[in] dev: the ubcore device;
 */
void ubcore_unregister_device(struct ubcore_device *dev);

#endif
+11 −0
Original line number Diff line number Diff line
@@ -134,6 +134,13 @@ struct ubcore_ops {
	 * @return: 0 on success, other value on error
	 */
	int (*set_eid)(struct ubcore_device *dev, union ubcore_eid eid);
	/**
	 * query device attributes
	 * @param[in] dev: the ub device handle;
	 * @param[out] attr: attributes for the driver to fill in
	 * @return: 0 on success, other value on error
	 */
	int (*query_device_attr)(struct ubcore_device *dev, struct ubcore_device_attr *attr);
	/**
	 * set ub network address
	 * @param[in] dev: the ub device handle;
@@ -175,6 +182,10 @@ struct ubcore_device {
	struct attribute_group *group[UBCORE_MAX_ATTR_GROUP]; /* driver may fill group [1] */
	/* driver fills end */

	/* port management */
	struct kobject *ports_parent; /* kobject parent of the ports in the port list */
	struct list_head port_list;

	/* For ubcore client */
	spinlock_t client_ctx_lock;
	struct list_head client_ctx_list;
+7 −1
Original line number Diff line number Diff line
@@ -32,7 +32,13 @@
 * @return: 0 on success, other value on error
 */
int ubcore_set_eid(struct ubcore_device *dev, union ubcore_eid *eid);

/**
 * query device attributes
 * @param[in] dev: the ubcore_device handle;
 * @param[out] attr: attributes returned to client
 * @return: 0 on success, other value on error
 */
int ubcore_query_device_attr(struct ubcore_device *dev, struct ubcore_device_attr *attr);
/**
 * query stats
 * @param[in] dev: the ubcore_device handle;