xref: /linux/drivers/dibs/dibs_loopback.c (revision 719c3b67bb7ea95bb8158b03c75641c8fc8f94a0)
1cb990a45SAlexandra Winter // SPDX-License-Identifier: GPL-2.0
2cb990a45SAlexandra Winter /*
3cb990a45SAlexandra Winter  *  Functions for dibs loopback/loopback-ism device.
4cb990a45SAlexandra Winter  *
5cb990a45SAlexandra Winter  *  Copyright (c) 2024, Alibaba Inc.
6cb990a45SAlexandra Winter  *
7cb990a45SAlexandra Winter  *  Author: Wen Gu <guwen@linux.alibaba.com>
8cb990a45SAlexandra Winter  *          Tony Lu <tonylu@linux.alibaba.com>
9cb990a45SAlexandra Winter  *
10cb990a45SAlexandra Winter  */
11cb990a45SAlexandra Winter 
12cb990a45SAlexandra Winter #include <linux/dibs.h>
13cb990a45SAlexandra Winter #include <linux/slab.h>
14cb990a45SAlexandra Winter #include <linux/types.h>
15cb990a45SAlexandra Winter 
16cb990a45SAlexandra Winter #include "dibs_loopback.h"
17cb990a45SAlexandra Winter 
18845c334aSJulian Ruess static const char dibs_lo_dev_name[] = "lo";
19cb990a45SAlexandra Winter /* global loopback device */
20cb990a45SAlexandra Winter static struct dibs_lo_dev *lo_dev;
21cb990a45SAlexandra Winter 
2269baaac9SAlexandra Winter static u16 dibs_lo_get_fabric_id(struct dibs_dev *dibs)
2369baaac9SAlexandra Winter {
2469baaac9SAlexandra Winter 	return DIBS_LOOPBACK_FABRIC;
2569baaac9SAlexandra Winter }
2669baaac9SAlexandra Winter 
27*719c3b67SAlexandra Winter static int dibs_lo_query_rgid(struct dibs_dev *dibs, const uuid_t *rgid,
28*719c3b67SAlexandra Winter 			      u32 vid_valid, u32 vid)
29*719c3b67SAlexandra Winter {
30*719c3b67SAlexandra Winter 	/* rgid should be the same as lgid */
31*719c3b67SAlexandra Winter 	if (!uuid_equal(rgid, &dibs->gid))
32*719c3b67SAlexandra Winter 		return -ENETUNREACH;
33*719c3b67SAlexandra Winter 	return 0;
34*719c3b67SAlexandra Winter }
35*719c3b67SAlexandra Winter 
3669baaac9SAlexandra Winter static const struct dibs_dev_ops dibs_lo_ops = {
3769baaac9SAlexandra Winter 	.get_fabric_id = dibs_lo_get_fabric_id,
38*719c3b67SAlexandra Winter 	.query_remote_gid = dibs_lo_query_rgid,
3969baaac9SAlexandra Winter };
4069baaac9SAlexandra Winter 
41cb990a45SAlexandra Winter static int dibs_lo_dev_probe(void)
42cb990a45SAlexandra Winter {
43cb990a45SAlexandra Winter 	struct dibs_lo_dev *ldev;
44cb990a45SAlexandra Winter 	struct dibs_dev *dibs;
45cb990a45SAlexandra Winter 	int ret;
46cb990a45SAlexandra Winter 
47cb990a45SAlexandra Winter 	ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
48cb990a45SAlexandra Winter 	if (!ldev)
49cb990a45SAlexandra Winter 		return -ENOMEM;
50cb990a45SAlexandra Winter 
51cb990a45SAlexandra Winter 	dibs = dibs_dev_alloc();
52cb990a45SAlexandra Winter 	if (!dibs) {
53cb990a45SAlexandra Winter 		kfree(ldev);
54cb990a45SAlexandra Winter 		return -ENOMEM;
55cb990a45SAlexandra Winter 	}
56cb990a45SAlexandra Winter 
57cb990a45SAlexandra Winter 	ldev->dibs = dibs;
5869baaac9SAlexandra Winter 	dibs->drv_priv = ldev;
5905e68d8dSAlexandra Winter 	uuid_gen(&dibs->gid);
6069baaac9SAlexandra Winter 	dibs->ops = &dibs_lo_ops;
61cb990a45SAlexandra Winter 
62845c334aSJulian Ruess 	dibs->dev.parent = NULL;
63845c334aSJulian Ruess 	dev_set_name(&dibs->dev, "%s", dibs_lo_dev_name);
64845c334aSJulian Ruess 
65cb990a45SAlexandra Winter 	ret = dibs_dev_add(dibs);
66cb990a45SAlexandra Winter 	if (ret)
67cb990a45SAlexandra Winter 		goto err_reg;
68cb990a45SAlexandra Winter 	lo_dev = ldev;
69cb990a45SAlexandra Winter 	return 0;
70cb990a45SAlexandra Winter 
71cb990a45SAlexandra Winter err_reg:
72cb990a45SAlexandra Winter 	/* pairs with dibs_dev_alloc() */
73845c334aSJulian Ruess 	put_device(&dibs->dev);
74cb990a45SAlexandra Winter 	kfree(ldev);
75cb990a45SAlexandra Winter 
76cb990a45SAlexandra Winter 	return ret;
77cb990a45SAlexandra Winter }
78cb990a45SAlexandra Winter 
79cb990a45SAlexandra Winter static void dibs_lo_dev_remove(void)
80cb990a45SAlexandra Winter {
81cb990a45SAlexandra Winter 	if (!lo_dev)
82cb990a45SAlexandra Winter 		return;
83cb990a45SAlexandra Winter 
84845c334aSJulian Ruess 	dibs_dev_del(lo_dev->dibs);
85cb990a45SAlexandra Winter 	/* pairs with dibs_dev_alloc() */
86845c334aSJulian Ruess 	put_device(&lo_dev->dibs->dev);
87cb990a45SAlexandra Winter 	kfree(lo_dev);
88cb990a45SAlexandra Winter 	lo_dev = NULL;
89cb990a45SAlexandra Winter }
90cb990a45SAlexandra Winter 
91cb990a45SAlexandra Winter int dibs_loopback_init(void)
92cb990a45SAlexandra Winter {
93cb990a45SAlexandra Winter 	return dibs_lo_dev_probe();
94cb990a45SAlexandra Winter }
95cb990a45SAlexandra Winter 
96cb990a45SAlexandra Winter void dibs_loopback_exit(void)
97cb990a45SAlexandra Winter {
98cb990a45SAlexandra Winter 	dibs_lo_dev_remove();
99cb990a45SAlexandra Winter }
100