GNU Linux-libre 5.10.217-gnu1
[releases.git] / drivers / infiniband / sw / rxe / rxe_mcast.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /*
3  * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
4  * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
5  */
6
7 #include "rxe.h"
8 #include "rxe_loc.h"
9
10 int rxe_mcast_get_grp(struct rxe_dev *rxe, union ib_gid *mgid,
11                       struct rxe_mc_grp **grp_p)
12 {
13         int err;
14         struct rxe_mc_grp *grp;
15
16         if (rxe->attr.max_mcast_qp_attach == 0) {
17                 err = -EINVAL;
18                 goto err1;
19         }
20
21         grp = rxe_pool_get_key(&rxe->mc_grp_pool, mgid);
22         if (grp)
23                 goto done;
24
25         grp = rxe_alloc(&rxe->mc_grp_pool);
26         if (!grp) {
27                 err = -ENOMEM;
28                 goto err1;
29         }
30
31         INIT_LIST_HEAD(&grp->qp_list);
32         spin_lock_init(&grp->mcg_lock);
33         grp->rxe = rxe;
34
35         rxe_add_key(grp, mgid);
36
37         err = rxe_mcast_add(rxe, mgid);
38         if (err)
39                 goto err2;
40
41 done:
42         *grp_p = grp;
43         return 0;
44
45 err2:
46         rxe_drop_ref(grp);
47 err1:
48         return err;
49 }
50
51 int rxe_mcast_add_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp,
52                            struct rxe_mc_grp *grp)
53 {
54         int err;
55         struct rxe_mc_elem *elem;
56
57         /* check to see of the qp is already a member of the group */
58         spin_lock_bh(&qp->grp_lock);
59         spin_lock_bh(&grp->mcg_lock);
60         list_for_each_entry(elem, &grp->qp_list, qp_list) {
61                 if (elem->qp == qp) {
62                         err = 0;
63                         goto out;
64                 }
65         }
66
67         if (grp->num_qp >= rxe->attr.max_mcast_qp_attach) {
68                 err = -ENOMEM;
69                 goto out;
70         }
71
72         elem = rxe_alloc(&rxe->mc_elem_pool);
73         if (!elem) {
74                 err = -ENOMEM;
75                 goto out;
76         }
77
78         /* each qp holds a ref on the grp */
79         rxe_add_ref(grp);
80
81         grp->num_qp++;
82         elem->qp = qp;
83         elem->grp = grp;
84
85         list_add(&elem->qp_list, &grp->qp_list);
86         list_add(&elem->grp_list, &qp->grp_list);
87
88         err = 0;
89 out:
90         spin_unlock_bh(&grp->mcg_lock);
91         spin_unlock_bh(&qp->grp_lock);
92         return err;
93 }
94
95 int rxe_mcast_drop_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp,
96                             union ib_gid *mgid)
97 {
98         struct rxe_mc_grp *grp;
99         struct rxe_mc_elem *elem, *tmp;
100
101         grp = rxe_pool_get_key(&rxe->mc_grp_pool, mgid);
102         if (!grp)
103                 goto err1;
104
105         spin_lock_bh(&qp->grp_lock);
106         spin_lock_bh(&grp->mcg_lock);
107
108         list_for_each_entry_safe(elem, tmp, &grp->qp_list, qp_list) {
109                 if (elem->qp == qp) {
110                         list_del(&elem->qp_list);
111                         list_del(&elem->grp_list);
112                         grp->num_qp--;
113
114                         spin_unlock_bh(&grp->mcg_lock);
115                         spin_unlock_bh(&qp->grp_lock);
116                         rxe_drop_ref(elem);
117                         rxe_drop_ref(grp);      /* ref held by QP */
118                         rxe_drop_ref(grp);      /* ref from get_key */
119                         return 0;
120                 }
121         }
122
123         spin_unlock_bh(&grp->mcg_lock);
124         spin_unlock_bh(&qp->grp_lock);
125         rxe_drop_ref(grp);                      /* ref from get_key */
126 err1:
127         return -EINVAL;
128 }
129
130 void rxe_drop_all_mcast_groups(struct rxe_qp *qp)
131 {
132         struct rxe_mc_grp *grp;
133         struct rxe_mc_elem *elem;
134
135         while (1) {
136                 spin_lock_bh(&qp->grp_lock);
137                 if (list_empty(&qp->grp_list)) {
138                         spin_unlock_bh(&qp->grp_lock);
139                         break;
140                 }
141                 elem = list_first_entry(&qp->grp_list, struct rxe_mc_elem,
142                                         grp_list);
143                 list_del(&elem->grp_list);
144                 spin_unlock_bh(&qp->grp_lock);
145
146                 grp = elem->grp;
147                 spin_lock_bh(&grp->mcg_lock);
148                 list_del(&elem->qp_list);
149                 grp->num_qp--;
150                 spin_unlock_bh(&grp->mcg_lock);
151                 rxe_drop_ref(grp);
152                 rxe_drop_ref(elem);
153         }
154 }
155
156 void rxe_mc_cleanup(struct rxe_pool_entry *arg)
157 {
158         struct rxe_mc_grp *grp = container_of(arg, typeof(*grp), pelem);
159         struct rxe_dev *rxe = grp->rxe;
160
161         rxe_drop_key(grp);
162         rxe_mcast_delete(rxe, &grp->mgid);
163 }