f84aa1bf570c33f68d13bfd7e8bb81850ff6e061
[dpdk.git] / drivers / net / octeontx2 / otx2_mcast.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2019 Marvell International Ltd.
3  */
4
5 #include "otx2_ethdev.h"
6
7 static int
8 nix_mc_addr_list_free(struct otx2_eth_dev *dev, uint32_t entry_count)
9 {
10         struct npc_mcam_free_entry_req *req;
11         struct otx2_mbox *mbox = dev->mbox;
12         struct mcast_entry *entry;
13         int rc = 0;
14
15         if (entry_count == 0)
16                 goto exit;
17
18         TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) {
19                 req = otx2_mbox_alloc_msg_npc_mcam_free_entry(mbox);
20                 req->entry = entry->mcam_index;
21
22                 rc = otx2_mbox_process_msg(mbox, NULL);
23                 if (rc < 0)
24                         goto exit;
25
26                 TAILQ_REMOVE(&dev->mc_fltr_tbl, entry, next);
27                 rte_free(entry);
28                 entry_count--;
29
30                 if (entry_count == 0)
31                         break;
32         }
33
34         if (entry == NULL)
35                 dev->mc_tbl_set = false;
36
37 exit:
38         return rc;
39 }
40
41 static int
42 nix_hw_update_mc_addr_list(struct rte_eth_dev *eth_dev)
43 {
44         struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
45         struct otx2_npc_flow_info *npc = &dev->npc_flow;
46         volatile uint8_t *key_data, *key_mask;
47         struct npc_mcam_write_entry_req *req;
48         struct otx2_mbox *mbox = dev->mbox;
49         struct npc_xtract_info *x_info;
50         uint64_t mcam_data, mcam_mask;
51         struct mcast_entry *entry;
52         otx2_dxcfg_t *ld_cfg;
53         uint8_t *mac_addr;
54         uint64_t action;
55         int idx, rc = 0;
56
57         ld_cfg = &npc->prx_dxcfg;
58         /* Get ETH layer profile info for populating mcam entries */
59         x_info = &(*ld_cfg)[NPC_MCAM_RX][NPC_LID_LA][NPC_LT_LA_ETHER].xtract[0];
60
61         TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) {
62                 req = otx2_mbox_alloc_msg_npc_mcam_write_entry(mbox);
63                 if (req == NULL) {
64                         /* The mbox memory buffer can be full.
65                          * Flush it and retry
66                          */
67                         otx2_mbox_msg_send(mbox, 0);
68                         rc = otx2_mbox_wait_for_rsp(mbox, 0);
69                         if (rc < 0)
70                                 goto exit;
71
72                         req = otx2_mbox_alloc_msg_npc_mcam_write_entry(mbox);
73                         if (req == NULL) {
74                                 rc = -ENOMEM;
75                                 goto exit;
76                         }
77                 }
78                 req->entry = entry->mcam_index;
79                 req->intf = NPC_MCAM_RX;
80                 req->enable_entry = 1;
81
82                 /* Channel base extracted to KW0[11:0] */
83                 req->entry_data.kw[0] = dev->rx_chan_base;
84                 req->entry_data.kw_mask[0] = RTE_LEN2MASK(12, uint64_t);
85
86                 /* Update mcam address */
87                 key_data = (volatile uint8_t *)req->entry_data.kw;
88                 key_mask = (volatile uint8_t *)req->entry_data.kw_mask;
89
90                 mcam_data = 0ull;
91                 mcam_mask = RTE_LEN2MASK(48, uint64_t);
92                 mac_addr = &entry->mcast_mac.addr_bytes[0];
93                 for (idx = RTE_ETHER_ADDR_LEN - 1; idx >= 0; idx--)
94                         mcam_data |= ((uint64_t)*mac_addr++) << (8 * idx);
95
96                 otx2_mbox_memcpy(key_data + x_info->key_off,
97                                  &mcam_data, x_info->len);
98                 otx2_mbox_memcpy(key_mask + x_info->key_off,
99                                  &mcam_mask, x_info->len);
100
101                 action = NIX_RX_ACTIONOP_UCAST;
102
103                 if (eth_dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_RSS) {
104                         action = NIX_RX_ACTIONOP_RSS;
105                         action |= (uint64_t)(dev->rss_info.alg_idx) << 56;
106                 }
107
108                 action |= ((uint64_t)otx2_pfvf_func(dev->pf, dev->vf)) << 4;
109                 req->entry_data.action = action;
110         }
111
112         otx2_mbox_msg_send(mbox, 0);
113         rc = otx2_mbox_wait_for_rsp(mbox, 0);
114
115 exit:
116         return rc;
117 }
118
119 int
120 otx2_nix_mc_addr_list_install(struct rte_eth_dev *eth_dev)
121 {
122         struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
123         struct npc_mcam_alloc_entry_req *req;
124         struct npc_mcam_alloc_entry_rsp *rsp;
125         struct otx2_mbox *mbox = dev->mbox;
126         uint32_t entry_count = 0, idx  = 0;
127         struct mcast_entry *entry;
128         int rc = 0;
129
130         if (!dev->mc_tbl_set)
131                 return 0;
132
133         TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next)
134                 entry_count++;
135
136         req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(mbox);
137         req->priority = NPC_MCAM_ANY_PRIO;
138         req->count = entry_count;
139
140         rc = otx2_mbox_process_msg(mbox, (void *)&rsp);
141         if (rc || rsp->count  < entry_count) {
142                 otx2_err("Failed to allocate required mcam entries");
143                 goto exit;
144         }
145
146         TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next)
147                 entry->mcam_index = rsp->entry_list[idx];
148
149         rc = nix_hw_update_mc_addr_list(eth_dev);
150
151 exit:
152         return rc;
153 }
154
155 int
156 otx2_nix_mc_addr_list_uninstall(struct rte_eth_dev *eth_dev)
157 {
158         struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
159         struct npc_mcam_free_entry_req *req;
160         struct otx2_mbox *mbox = dev->mbox;
161         struct mcast_entry *entry;
162         int rc = 0;
163
164         if (!dev->mc_tbl_set)
165                 return 0;
166
167         TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) {
168                 req = otx2_mbox_alloc_msg_npc_mcam_free_entry(mbox);
169                 if (req == NULL) {
170                         otx2_mbox_msg_send(mbox, 0);
171                         rc = otx2_mbox_wait_for_rsp(mbox, 0);
172                         if (rc < 0)
173                                 goto exit;
174
175                         req = otx2_mbox_alloc_msg_npc_mcam_free_entry(mbox);
176                         if (req == NULL) {
177                                 rc = -ENOMEM;
178                                 goto exit;
179                         }
180                 }
181                 req->entry = entry->mcam_index;
182         }
183
184         otx2_mbox_msg_send(mbox, 0);
185         rc = otx2_mbox_wait_for_rsp(mbox, 0);
186
187 exit:
188         return rc;
189 }
190
191 static int
192 nix_setup_mc_addr_list(struct otx2_eth_dev *dev,
193                        struct rte_ether_addr *mc_addr_set)
194 {
195         struct npc_mcam_ena_dis_entry_req *req;
196         struct otx2_mbox *mbox = dev->mbox;
197         struct mcast_entry *entry;
198         uint32_t idx = 0;
199         int rc = 0;
200
201         /* Populate PMD's mcast list with given mcast mac addresses and
202          * disable all mcam entries pertaining to the mcast list.
203          */
204         TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) {
205                 rte_memcpy(&entry->mcast_mac, &mc_addr_set[idx++],
206                            RTE_ETHER_ADDR_LEN);
207
208                 req = otx2_mbox_alloc_msg_npc_mcam_dis_entry(mbox);
209                 if (req == NULL) {
210                         otx2_mbox_msg_send(mbox, 0);
211                         rc = otx2_mbox_wait_for_rsp(mbox, 0);
212                         if (rc < 0)
213                                 goto exit;
214
215                         req = otx2_mbox_alloc_msg_npc_mcam_dis_entry(mbox);
216                         if (req == NULL) {
217                                 rc = -ENOMEM;
218                                 goto exit;
219                         }
220                 }
221                 req->entry = entry->mcam_index;
222         }
223
224         otx2_mbox_msg_send(mbox, 0);
225         rc = otx2_mbox_wait_for_rsp(mbox, 0);
226
227 exit:
228         return rc;
229 }
230
231 int
232 otx2_nix_set_mc_addr_list(struct rte_eth_dev *eth_dev,
233                           struct rte_ether_addr *mc_addr_set,
234                           uint32_t nb_mc_addr)
235 {
236         struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
237         struct npc_mcam_alloc_entry_req *req;
238         struct npc_mcam_alloc_entry_rsp *rsp;
239         struct otx2_mbox *mbox = dev->mbox;
240         uint32_t idx, priv_count = 0;
241         struct mcast_entry *entry;
242         int rc = 0;
243
244         if (otx2_dev_is_vf(dev))
245                 return -ENOTSUP;
246
247         TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next)
248                 priv_count++;
249
250         if (nb_mc_addr == 0 || mc_addr_set == NULL) {
251                 /* Free existing list if new list is null */
252                 nb_mc_addr = priv_count;
253                 goto exit;
254         }
255
256         for (idx = 0; idx < nb_mc_addr; idx++) {
257                 if (!rte_is_multicast_ether_addr(&mc_addr_set[idx]))
258                         return -EINVAL;
259         }
260
261         /* New list is bigger than the existing list,
262          * allocate mcam entries for the extra entries.
263          */
264         if (nb_mc_addr > priv_count) {
265                 req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(mbox);
266                 req->priority = NPC_MCAM_ANY_PRIO;
267                 req->count = nb_mc_addr - priv_count;
268
269                 rc = otx2_mbox_process_msg(mbox, (void *)&rsp);
270                 if (rc || (rsp->count + priv_count < nb_mc_addr)) {
271                         otx2_err("Failed to allocate required entries");
272                         nb_mc_addr = priv_count;
273                         goto exit;
274                 }
275
276                 /* Append new mcam entries to the existing mc list */
277                 for (idx = 0; idx < rsp->count; idx++) {
278                         entry = rte_zmalloc("otx2_nix_mc_entry",
279                                             sizeof(struct mcast_entry), 0);
280                         if (!entry) {
281                                 otx2_err("Failed to allocate memory");
282                                 nb_mc_addr = priv_count;
283                                 rc = -ENOMEM;
284                                 goto exit;
285                         }
286                         entry->mcam_index = rsp->entry_list[idx];
287                         TAILQ_INSERT_HEAD(&dev->mc_fltr_tbl, entry, next);
288                 }
289         } else {
290                 /* Free the extra mcam entries if the new list is smaller
291                  * than exiting list.
292                  */
293                 nix_mc_addr_list_free(dev, priv_count - nb_mc_addr);
294         }
295
296
297         /* Now mc_fltr_tbl has the required number of mcam entries,
298          * Traverse through it and add new multicast filter table entries.
299          */
300         rc = nix_setup_mc_addr_list(dev, mc_addr_set);
301         if (rc < 0)
302                 goto exit;
303
304         rc = nix_hw_update_mc_addr_list(eth_dev);
305         if (rc < 0)
306                 goto exit;
307
308         dev->mc_tbl_set = true;
309
310         return 0;
311
312 exit:
313         nix_mc_addr_list_free(dev, nb_mc_addr);
314         return rc;
315 }
316
317 void
318 otx2_nix_mc_filter_init(struct otx2_eth_dev *dev)
319 {
320         if (otx2_dev_is_vf(dev))
321                 return;
322
323         TAILQ_INIT(&dev->mc_fltr_tbl);
324 }
325
326 void
327 otx2_nix_mc_filter_fini(struct otx2_eth_dev *dev)
328 {
329         struct mcast_entry *entry;
330         uint32_t count = 0;
331
332         if (otx2_dev_is_vf(dev))
333                 return;
334
335         TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next)
336                 count++;
337
338         nix_mc_addr_list_free(dev, count);
339 }