net/sfc/base: import libefx base
[dpdk.git] / drivers / net / sfc / base / efx_mac.c
1 /*
2  * Copyright (c) 2007-2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include "efx.h"
32 #include "efx_impl.h"
33
34         __checkReturn                   efx_rc_t
35 efx_mac_pdu_set(
36         __in                            efx_nic_t *enp,
37         __in                            size_t pdu)
38 {
39         efx_port_t *epp = &(enp->en_port);
40         const efx_mac_ops_t *emop = epp->ep_emop;
41         uint32_t old_pdu;
42         efx_rc_t rc;
43
44         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
45         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
46         EFSYS_ASSERT(emop != NULL);
47
48         if (pdu < EFX_MAC_PDU_MIN) {
49                 rc = EINVAL;
50                 goto fail1;
51         }
52
53         if (pdu > EFX_MAC_PDU_MAX) {
54                 rc = EINVAL;
55                 goto fail2;
56         }
57
58         old_pdu = epp->ep_mac_pdu;
59         epp->ep_mac_pdu = (uint32_t)pdu;
60         if ((rc = emop->emo_pdu_set(enp)) != 0)
61                 goto fail3;
62
63         return (0);
64
65 fail3:
66         EFSYS_PROBE(fail3);
67
68         epp->ep_mac_pdu = old_pdu;
69
70 fail2:
71         EFSYS_PROBE(fail2);
72 fail1:
73         EFSYS_PROBE1(fail1, efx_rc_t, rc);
74
75         return (rc);
76 }
77
78         __checkReturn   efx_rc_t
79 efx_mac_pdu_get(
80         __in            efx_nic_t *enp,
81         __out           size_t *pdu)
82 {
83         efx_port_t *epp = &(enp->en_port);
84         const efx_mac_ops_t *emop = epp->ep_emop;
85         efx_rc_t rc;
86
87         if ((rc = emop->emo_pdu_get(enp, pdu)) != 0)
88                 goto fail1;
89
90         return (0);
91
92 fail1:
93         EFSYS_PROBE1(fail1, efx_rc_t, rc);
94
95         return (rc);
96 }
97
98         __checkReturn                   efx_rc_t
99 efx_mac_addr_set(
100         __in                            efx_nic_t *enp,
101         __in                            uint8_t *addr)
102 {
103         efx_port_t *epp = &(enp->en_port);
104         const efx_mac_ops_t *emop = epp->ep_emop;
105         uint8_t old_addr[6];
106         uint32_t oui;
107         efx_rc_t rc;
108
109         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
110         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
111
112         if (EFX_MAC_ADDR_IS_MULTICAST(addr)) {
113                 rc = EINVAL;
114                 goto fail1;
115         }
116
117         oui = addr[0] << 16 | addr[1] << 8 | addr[2];
118         if (oui == 0x000000) {
119                 rc = EINVAL;
120                 goto fail2;
121         }
122
123         EFX_MAC_ADDR_COPY(old_addr, epp->ep_mac_addr);
124         EFX_MAC_ADDR_COPY(epp->ep_mac_addr, addr);
125         if ((rc = emop->emo_addr_set(enp)) != 0)
126                 goto fail3;
127
128         return (0);
129
130 fail3:
131         EFSYS_PROBE(fail3);
132
133         EFX_MAC_ADDR_COPY(epp->ep_mac_addr, old_addr);
134
135 fail2:
136         EFSYS_PROBE(fail2);
137 fail1:
138         EFSYS_PROBE1(fail1, efx_rc_t, rc);
139
140         return (rc);
141 }
142
143         __checkReturn                   efx_rc_t
144 efx_mac_filter_set(
145         __in                            efx_nic_t *enp,
146         __in                            boolean_t all_unicst,
147         __in                            boolean_t mulcst,
148         __in                            boolean_t all_mulcst,
149         __in                            boolean_t brdcst)
150 {
151         efx_port_t *epp = &(enp->en_port);
152         const efx_mac_ops_t *emop = epp->ep_emop;
153         boolean_t old_all_unicst;
154         boolean_t old_mulcst;
155         boolean_t old_all_mulcst;
156         boolean_t old_brdcst;
157         efx_rc_t rc;
158
159         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
160         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
161
162         old_all_unicst = epp->ep_all_unicst;
163         old_mulcst = epp->ep_mulcst;
164         old_all_mulcst = epp->ep_all_mulcst;
165         old_brdcst = epp->ep_brdcst;
166
167         epp->ep_all_unicst = all_unicst;
168         epp->ep_mulcst = mulcst;
169         epp->ep_all_mulcst = all_mulcst;
170         epp->ep_brdcst = brdcst;
171
172         if ((rc = emop->emo_reconfigure(enp)) != 0)
173                 goto fail1;
174
175         return (0);
176
177 fail1:
178         EFSYS_PROBE1(fail1, efx_rc_t, rc);
179
180         epp->ep_all_unicst = old_all_unicst;
181         epp->ep_mulcst = old_mulcst;
182         epp->ep_all_mulcst = old_all_mulcst;
183         epp->ep_brdcst = old_brdcst;
184
185         return (rc);
186 }
187
188         __checkReturn                   efx_rc_t
189 efx_mac_drain(
190         __in                            efx_nic_t *enp,
191         __in                            boolean_t enabled)
192 {
193         efx_port_t *epp = &(enp->en_port);
194         const efx_mac_ops_t *emop = epp->ep_emop;
195         efx_rc_t rc;
196
197         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
198         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
199         EFSYS_ASSERT(emop != NULL);
200
201         if (epp->ep_mac_drain == enabled)
202                 return (0);
203
204         epp->ep_mac_drain = enabled;
205
206         if ((rc = emop->emo_reconfigure(enp)) != 0)
207                 goto fail1;
208
209         return (0);
210
211 fail1:
212         EFSYS_PROBE1(fail1, efx_rc_t, rc);
213
214         return (rc);
215 }
216
217         __checkReturn   efx_rc_t
218 efx_mac_up(
219         __in            efx_nic_t *enp,
220         __out           boolean_t *mac_upp)
221 {
222         efx_port_t *epp = &(enp->en_port);
223         const efx_mac_ops_t *emop = epp->ep_emop;
224         efx_rc_t rc;
225
226         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
227         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
228
229         if ((rc = emop->emo_up(enp, mac_upp)) != 0)
230                 goto fail1;
231
232         return (0);
233
234 fail1:
235         EFSYS_PROBE1(fail1, efx_rc_t, rc);
236
237         return (rc);
238 }
239
240         __checkReturn                   efx_rc_t
241 efx_mac_fcntl_set(
242         __in                            efx_nic_t *enp,
243         __in                            unsigned int fcntl,
244         __in                            boolean_t autoneg)
245 {
246         efx_port_t *epp = &(enp->en_port);
247         const efx_mac_ops_t *emop = epp->ep_emop;
248         const efx_phy_ops_t *epop = epp->ep_epop;
249         unsigned int old_fcntl;
250         boolean_t old_autoneg;
251         unsigned int old_adv_cap;
252         efx_rc_t rc;
253
254         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
255         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
256
257         if ((fcntl & ~(EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE)) != 0) {
258                 rc = EINVAL;
259                 goto fail1;
260         }
261
262         /*
263          * Ignore a request to set flow control auto-negotiation
264          * if the PHY doesn't support it.
265          */
266         if (~epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
267                 autoneg = B_FALSE;
268
269         old_fcntl = epp->ep_fcntl;
270         old_autoneg = epp->ep_fcntl_autoneg;
271         old_adv_cap = epp->ep_adv_cap_mask;
272
273         epp->ep_fcntl = fcntl;
274         epp->ep_fcntl_autoneg = autoneg;
275
276         /*
277          * Always encode the flow control settings in the advertised
278          * capabilities even if we are not trying to auto-negotiate
279          * them and reconfigure both the PHY and the MAC.
280          */
281         if (fcntl & EFX_FCNTL_RESPOND)
282                 epp->ep_adv_cap_mask |=    (1 << EFX_PHY_CAP_PAUSE |
283                                             1 << EFX_PHY_CAP_ASYM);
284         else
285                 epp->ep_adv_cap_mask &=   ~(1 << EFX_PHY_CAP_PAUSE |
286                                             1 << EFX_PHY_CAP_ASYM);
287
288         if (fcntl & EFX_FCNTL_GENERATE)
289                 epp->ep_adv_cap_mask ^= (1 << EFX_PHY_CAP_ASYM);
290
291         if ((rc = epop->epo_reconfigure(enp)) != 0)
292                 goto fail2;
293
294         if ((rc = emop->emo_reconfigure(enp)) != 0)
295                 goto fail3;
296
297         return (0);
298
299 fail3:
300         EFSYS_PROBE(fail3);
301
302 fail2:
303         EFSYS_PROBE(fail2);
304
305         epp->ep_fcntl = old_fcntl;
306         epp->ep_fcntl_autoneg = old_autoneg;
307         epp->ep_adv_cap_mask = old_adv_cap;
308
309 fail1:
310         EFSYS_PROBE1(fail1, efx_rc_t, rc);
311
312         return (rc);
313 }
314
315                         void
316 efx_mac_fcntl_get(
317         __in            efx_nic_t *enp,
318         __out           unsigned int *fcntl_wantedp,
319         __out           unsigned int *fcntl_linkp)
320 {
321         efx_port_t *epp = &(enp->en_port);
322         unsigned int wanted = 0;
323
324         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
325         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
326
327         /*
328          * Decode the requested flow control settings from the PHY
329          * advertised capabilities.
330          */
331         if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_PAUSE))
332                 wanted = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
333         if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_ASYM))
334                 wanted ^= EFX_FCNTL_GENERATE;
335
336         *fcntl_linkp = epp->ep_fcntl;
337         *fcntl_wantedp = wanted;
338 }
339
340         __checkReturn   efx_rc_t
341 efx_mac_multicast_list_set(
342         __in                            efx_nic_t *enp,
343         __in_ecount(6*count)            uint8_t const *addrs,
344         __in                            int count)
345 {
346         efx_port_t *epp = &(enp->en_port);
347         const efx_mac_ops_t *emop = epp->ep_emop;
348         uint8_t *old_mulcst_addr_list = NULL;
349         uint32_t old_mulcst_addr_count;
350         efx_rc_t rc;
351
352         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
353         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
354
355         if (count > EFX_MAC_MULTICAST_LIST_MAX) {
356                 rc = EINVAL;
357                 goto fail1;
358         }
359
360         old_mulcst_addr_count = epp->ep_mulcst_addr_count;
361         if (old_mulcst_addr_count > 0) {
362                 /* Allocate memory to store old list (instead of using stack) */
363                 EFSYS_KMEM_ALLOC(enp->en_esip,
364                                 old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
365                                 old_mulcst_addr_list);
366                 if (old_mulcst_addr_list == NULL) {
367                         rc = ENOMEM;
368                         goto fail2;
369                 }
370
371                 /* Save the old list in case we need to rollback */
372                 memcpy(old_mulcst_addr_list, epp->ep_mulcst_addr_list,
373                         old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
374         }
375
376         /* Store the new list */
377         memcpy(epp->ep_mulcst_addr_list, addrs,
378                 count * EFX_MAC_ADDR_LEN);
379         epp->ep_mulcst_addr_count = count;
380
381         if ((rc = emop->emo_multicast_list_set(enp)) != 0)
382                 goto fail3;
383
384         if (old_mulcst_addr_count > 0) {
385                 EFSYS_KMEM_FREE(enp->en_esip,
386                                 old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
387                                 old_mulcst_addr_list);
388         }
389
390         return (0);
391
392 fail3:
393         EFSYS_PROBE(fail3);
394
395         /* Restore original list on failure */
396         epp->ep_mulcst_addr_count = old_mulcst_addr_count;
397         if (old_mulcst_addr_count > 0) {
398                 memcpy(epp->ep_mulcst_addr_list, old_mulcst_addr_list,
399                         old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
400
401                 EFSYS_KMEM_FREE(enp->en_esip,
402                                 old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
403                                 old_mulcst_addr_list);
404         }
405
406 fail2:
407         EFSYS_PROBE(fail2);
408
409 fail1:
410         EFSYS_PROBE1(fail1, efx_rc_t, rc);
411
412         return (rc);
413
414 }
415
416         __checkReturn   efx_rc_t
417 efx_mac_filter_default_rxq_set(
418         __in            efx_nic_t *enp,
419         __in            efx_rxq_t *erp,
420         __in            boolean_t using_rss)
421 {
422         efx_port_t *epp = &(enp->en_port);
423         const efx_mac_ops_t *emop = epp->ep_emop;
424         efx_rc_t rc;
425
426         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
427         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
428
429         if (emop->emo_filter_default_rxq_set != NULL) {
430                 rc = emop->emo_filter_default_rxq_set(enp, erp, using_rss);
431                 if (rc != 0)
432                         goto fail1;
433         }
434
435         return (0);
436
437 fail1:
438         EFSYS_PROBE1(fail1, efx_rc_t, rc);
439
440         return (rc);
441 }
442
443                         void
444 efx_mac_filter_default_rxq_clear(
445         __in            efx_nic_t *enp)
446 {
447         efx_port_t *epp = &(enp->en_port);
448         const efx_mac_ops_t *emop = epp->ep_emop;
449
450         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
451         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
452
453         if (emop->emo_filter_default_rxq_clear != NULL)
454                 emop->emo_filter_default_rxq_clear(enp);
455 }
456
457
458         __checkReturn                   efx_rc_t
459 efx_mac_select(
460         __in                            efx_nic_t *enp)
461 {
462         efx_port_t *epp = &(enp->en_port);
463         efx_mac_type_t type = EFX_MAC_INVALID;
464         const efx_mac_ops_t *emop;
465         int rc = EINVAL;
466
467         switch (enp->en_family) {
468
469         default:
470                 rc = EINVAL;
471                 goto fail1;
472         }
473
474         EFSYS_ASSERT(type != EFX_MAC_INVALID);
475         EFSYS_ASSERT3U(type, <, EFX_MAC_NTYPES);
476         EFSYS_ASSERT(emop != NULL);
477
478         epp->ep_emop = emop;
479         epp->ep_mac_type = type;
480
481         return (0);
482
483 fail1:
484         EFSYS_PROBE1(fail1, efx_rc_t, rc);
485
486         return (rc);
487 }
488
489