xref: /linux-6.15/net/smc/smc_loopback.c (revision 46ac6441)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Shared Memory Communications Direct over loopback-ism device.
4  *
5  *  Functions for loopback-ism device.
6  *
7  *  Copyright (c) 2024, Alibaba Inc.
8  *
9  *  Author: Wen Gu <[email protected]>
10  *          Tony Lu <[email protected]>
11  *
12  */
13 
14 #include <linux/device.h>
15 #include <linux/types.h>
16 #include <net/smc.h>
17 
18 #include "smc_ism.h"
19 #include "smc_loopback.h"
20 
21 static const char smc_lo_dev_name[] = "loopback-ism";
22 static struct smc_lo_dev *lo_dev;
23 
24 static const struct smcd_ops lo_ops = {
25 	.query_remote_gid	= NULL,
26 	.register_dmb		= NULL,
27 	.unregister_dmb		= NULL,
28 	.add_vlan_id		= NULL,
29 	.del_vlan_id		= NULL,
30 	.set_vlan_required	= NULL,
31 	.reset_vlan_required	= NULL,
32 	.signal_event		= NULL,
33 	.move_data		= NULL,
34 	.supports_v2		= NULL,
35 	.get_local_gid		= NULL,
36 	.get_chid		= NULL,
37 	.get_dev		= NULL,
38 };
39 
40 static struct smcd_dev *smcd_lo_alloc_dev(const struct smcd_ops *ops,
41 					  int max_dmbs)
42 {
43 	struct smcd_dev *smcd;
44 
45 	smcd = kzalloc(sizeof(*smcd), GFP_KERNEL);
46 	if (!smcd)
47 		return NULL;
48 
49 	smcd->conn = kcalloc(max_dmbs, sizeof(struct smc_connection *),
50 			     GFP_KERNEL);
51 	if (!smcd->conn)
52 		goto out_smcd;
53 
54 	smcd->ops = ops;
55 
56 	spin_lock_init(&smcd->lock);
57 	spin_lock_init(&smcd->lgr_lock);
58 	INIT_LIST_HEAD(&smcd->vlan);
59 	INIT_LIST_HEAD(&smcd->lgr_list);
60 	init_waitqueue_head(&smcd->lgrs_deleted);
61 	return smcd;
62 
63 out_smcd:
64 	kfree(smcd);
65 	return NULL;
66 }
67 
68 static int smcd_lo_register_dev(struct smc_lo_dev *ldev)
69 {
70 	struct smcd_dev *smcd;
71 
72 	smcd = smcd_lo_alloc_dev(&lo_ops, SMC_LO_MAX_DMBS);
73 	if (!smcd)
74 		return -ENOMEM;
75 	ldev->smcd = smcd;
76 	smcd->priv = ldev;
77 
78 	/* TODO:
79 	 * register loopback-ism to smcd_dev list.
80 	 */
81 	return 0;
82 }
83 
84 static void smcd_lo_unregister_dev(struct smc_lo_dev *ldev)
85 {
86 	struct smcd_dev *smcd = ldev->smcd;
87 
88 	/* TODO:
89 	 * unregister loopback-ism from smcd_dev list.
90 	 */
91 	kfree(smcd->conn);
92 	kfree(smcd);
93 }
94 
95 static int smc_lo_dev_init(struct smc_lo_dev *ldev)
96 {
97 	return smcd_lo_register_dev(ldev);
98 }
99 
100 static void smc_lo_dev_exit(struct smc_lo_dev *ldev)
101 {
102 	smcd_lo_unregister_dev(ldev);
103 }
104 
105 static void smc_lo_dev_release(struct device *dev)
106 {
107 	struct smc_lo_dev *ldev =
108 		container_of(dev, struct smc_lo_dev, dev);
109 
110 	kfree(ldev);
111 }
112 
113 static int smc_lo_dev_probe(void)
114 {
115 	struct smc_lo_dev *ldev;
116 	int ret;
117 
118 	ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
119 	if (!ldev)
120 		return -ENOMEM;
121 
122 	ldev->dev.parent = NULL;
123 	ldev->dev.release = smc_lo_dev_release;
124 	device_initialize(&ldev->dev);
125 	dev_set_name(&ldev->dev, smc_lo_dev_name);
126 
127 	ret = smc_lo_dev_init(ldev);
128 	if (ret)
129 		goto free_dev;
130 
131 	lo_dev = ldev; /* global loopback device */
132 	return 0;
133 
134 free_dev:
135 	put_device(&ldev->dev);
136 	return ret;
137 }
138 
139 static void smc_lo_dev_remove(void)
140 {
141 	if (!lo_dev)
142 		return;
143 
144 	smc_lo_dev_exit(lo_dev);
145 	put_device(&lo_dev->dev); /* device_initialize in smc_lo_dev_probe */
146 }
147 
148 int smc_loopback_init(void)
149 {
150 	return smc_lo_dev_probe();
151 }
152 
153 void smc_loopback_exit(void)
154 {
155 	smc_lo_dev_remove();
156 }
157