net/smc: introduce loopback-ism for SMC intra-OS shortcut
[linux-2.6-block.git] / net / smc / smc_loopback.c
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 <guwen@linux.alibaba.com>
10  *          Tony Lu <tonylu@linux.alibaba.com>
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 }