net/sfc/base: import MAC statistics
[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 #if EFSYS_OPT_SIENA
35
36 static  __checkReturn   efx_rc_t
37 siena_mac_multicast_list_set(
38         __in            efx_nic_t *enp);
39
40 #endif /* EFSYS_OPT_SIENA */
41
42 #if EFSYS_OPT_SIENA
43 static const efx_mac_ops_t      __efx_siena_mac_ops = {
44         siena_mac_poll,                         /* emo_poll */
45         siena_mac_up,                           /* emo_up */
46         siena_mac_reconfigure,                  /* emo_addr_set */
47         siena_mac_reconfigure,                  /* emo_pdu_set */
48         siena_mac_pdu_get,                      /* emo_pdu_get */
49         siena_mac_reconfigure,                  /* emo_reconfigure */
50         siena_mac_multicast_list_set,           /* emo_multicast_list_set */
51         NULL,                                   /* emo_filter_set_default_rxq */
52         NULL,                           /* emo_filter_default_rxq_clear */
53 #if EFSYS_OPT_MAC_STATS
54         siena_mac_stats_get_mask,               /* emo_stats_get_mask */
55         efx_mcdi_mac_stats_upload,              /* emo_stats_upload */
56         efx_mcdi_mac_stats_periodic,            /* emo_stats_periodic */
57         siena_mac_stats_update                  /* emo_stats_update */
58 #endif  /* EFSYS_OPT_MAC_STATS */
59 };
60 #endif  /* EFSYS_OPT_SIENA */
61
62 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
63 static const efx_mac_ops_t      __efx_ef10_mac_ops = {
64         ef10_mac_poll,                          /* emo_poll */
65         ef10_mac_up,                            /* emo_up */
66         ef10_mac_addr_set,                      /* emo_addr_set */
67         ef10_mac_pdu_set,                       /* emo_pdu_set */
68         ef10_mac_pdu_get,                       /* emo_pdu_get */
69         ef10_mac_reconfigure,                   /* emo_reconfigure */
70         ef10_mac_multicast_list_set,            /* emo_multicast_list_set */
71         ef10_mac_filter_default_rxq_set,        /* emo_filter_default_rxq_set */
72         ef10_mac_filter_default_rxq_clear,
73                                         /* emo_filter_default_rxq_clear */
74 #if EFSYS_OPT_MAC_STATS
75         ef10_mac_stats_get_mask,                /* emo_stats_get_mask */
76         efx_mcdi_mac_stats_upload,              /* emo_stats_upload */
77         efx_mcdi_mac_stats_periodic,            /* emo_stats_periodic */
78         ef10_mac_stats_update                   /* emo_stats_update */
79 #endif  /* EFSYS_OPT_MAC_STATS */
80 };
81 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
82
83         __checkReturn                   efx_rc_t
84 efx_mac_pdu_set(
85         __in                            efx_nic_t *enp,
86         __in                            size_t pdu)
87 {
88         efx_port_t *epp = &(enp->en_port);
89         const efx_mac_ops_t *emop = epp->ep_emop;
90         uint32_t old_pdu;
91         efx_rc_t rc;
92
93         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
94         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
95         EFSYS_ASSERT(emop != NULL);
96
97         if (pdu < EFX_MAC_PDU_MIN) {
98                 rc = EINVAL;
99                 goto fail1;
100         }
101
102         if (pdu > EFX_MAC_PDU_MAX) {
103                 rc = EINVAL;
104                 goto fail2;
105         }
106
107         old_pdu = epp->ep_mac_pdu;
108         epp->ep_mac_pdu = (uint32_t)pdu;
109         if ((rc = emop->emo_pdu_set(enp)) != 0)
110                 goto fail3;
111
112         return (0);
113
114 fail3:
115         EFSYS_PROBE(fail3);
116
117         epp->ep_mac_pdu = old_pdu;
118
119 fail2:
120         EFSYS_PROBE(fail2);
121 fail1:
122         EFSYS_PROBE1(fail1, efx_rc_t, rc);
123
124         return (rc);
125 }
126
127         __checkReturn   efx_rc_t
128 efx_mac_pdu_get(
129         __in            efx_nic_t *enp,
130         __out           size_t *pdu)
131 {
132         efx_port_t *epp = &(enp->en_port);
133         const efx_mac_ops_t *emop = epp->ep_emop;
134         efx_rc_t rc;
135
136         if ((rc = emop->emo_pdu_get(enp, pdu)) != 0)
137                 goto fail1;
138
139         return (0);
140
141 fail1:
142         EFSYS_PROBE1(fail1, efx_rc_t, rc);
143
144         return (rc);
145 }
146
147         __checkReturn                   efx_rc_t
148 efx_mac_addr_set(
149         __in                            efx_nic_t *enp,
150         __in                            uint8_t *addr)
151 {
152         efx_port_t *epp = &(enp->en_port);
153         const efx_mac_ops_t *emop = epp->ep_emop;
154         uint8_t old_addr[6];
155         uint32_t oui;
156         efx_rc_t rc;
157
158         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
159         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
160
161         if (EFX_MAC_ADDR_IS_MULTICAST(addr)) {
162                 rc = EINVAL;
163                 goto fail1;
164         }
165
166         oui = addr[0] << 16 | addr[1] << 8 | addr[2];
167         if (oui == 0x000000) {
168                 rc = EINVAL;
169                 goto fail2;
170         }
171
172         EFX_MAC_ADDR_COPY(old_addr, epp->ep_mac_addr);
173         EFX_MAC_ADDR_COPY(epp->ep_mac_addr, addr);
174         if ((rc = emop->emo_addr_set(enp)) != 0)
175                 goto fail3;
176
177         return (0);
178
179 fail3:
180         EFSYS_PROBE(fail3);
181
182         EFX_MAC_ADDR_COPY(epp->ep_mac_addr, old_addr);
183
184 fail2:
185         EFSYS_PROBE(fail2);
186 fail1:
187         EFSYS_PROBE1(fail1, efx_rc_t, rc);
188
189         return (rc);
190 }
191
192         __checkReturn                   efx_rc_t
193 efx_mac_filter_set(
194         __in                            efx_nic_t *enp,
195         __in                            boolean_t all_unicst,
196         __in                            boolean_t mulcst,
197         __in                            boolean_t all_mulcst,
198         __in                            boolean_t brdcst)
199 {
200         efx_port_t *epp = &(enp->en_port);
201         const efx_mac_ops_t *emop = epp->ep_emop;
202         boolean_t old_all_unicst;
203         boolean_t old_mulcst;
204         boolean_t old_all_mulcst;
205         boolean_t old_brdcst;
206         efx_rc_t rc;
207
208         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
209         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
210
211         old_all_unicst = epp->ep_all_unicst;
212         old_mulcst = epp->ep_mulcst;
213         old_all_mulcst = epp->ep_all_mulcst;
214         old_brdcst = epp->ep_brdcst;
215
216         epp->ep_all_unicst = all_unicst;
217         epp->ep_mulcst = mulcst;
218         epp->ep_all_mulcst = all_mulcst;
219         epp->ep_brdcst = brdcst;
220
221         if ((rc = emop->emo_reconfigure(enp)) != 0)
222                 goto fail1;
223
224         return (0);
225
226 fail1:
227         EFSYS_PROBE1(fail1, efx_rc_t, rc);
228
229         epp->ep_all_unicst = old_all_unicst;
230         epp->ep_mulcst = old_mulcst;
231         epp->ep_all_mulcst = old_all_mulcst;
232         epp->ep_brdcst = old_brdcst;
233
234         return (rc);
235 }
236
237         __checkReturn                   efx_rc_t
238 efx_mac_drain(
239         __in                            efx_nic_t *enp,
240         __in                            boolean_t enabled)
241 {
242         efx_port_t *epp = &(enp->en_port);
243         const efx_mac_ops_t *emop = epp->ep_emop;
244         efx_rc_t rc;
245
246         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
247         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
248         EFSYS_ASSERT(emop != NULL);
249
250         if (epp->ep_mac_drain == enabled)
251                 return (0);
252
253         epp->ep_mac_drain = enabled;
254
255         if ((rc = emop->emo_reconfigure(enp)) != 0)
256                 goto fail1;
257
258         return (0);
259
260 fail1:
261         EFSYS_PROBE1(fail1, efx_rc_t, rc);
262
263         return (rc);
264 }
265
266         __checkReturn   efx_rc_t
267 efx_mac_up(
268         __in            efx_nic_t *enp,
269         __out           boolean_t *mac_upp)
270 {
271         efx_port_t *epp = &(enp->en_port);
272         const efx_mac_ops_t *emop = epp->ep_emop;
273         efx_rc_t rc;
274
275         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
276         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
277
278         if ((rc = emop->emo_up(enp, mac_upp)) != 0)
279                 goto fail1;
280
281         return (0);
282
283 fail1:
284         EFSYS_PROBE1(fail1, efx_rc_t, rc);
285
286         return (rc);
287 }
288
289         __checkReturn                   efx_rc_t
290 efx_mac_fcntl_set(
291         __in                            efx_nic_t *enp,
292         __in                            unsigned int fcntl,
293         __in                            boolean_t autoneg)
294 {
295         efx_port_t *epp = &(enp->en_port);
296         const efx_mac_ops_t *emop = epp->ep_emop;
297         const efx_phy_ops_t *epop = epp->ep_epop;
298         unsigned int old_fcntl;
299         boolean_t old_autoneg;
300         unsigned int old_adv_cap;
301         efx_rc_t rc;
302
303         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
304         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
305
306         if ((fcntl & ~(EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE)) != 0) {
307                 rc = EINVAL;
308                 goto fail1;
309         }
310
311         /*
312          * Ignore a request to set flow control auto-negotiation
313          * if the PHY doesn't support it.
314          */
315         if (~epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
316                 autoneg = B_FALSE;
317
318         old_fcntl = epp->ep_fcntl;
319         old_autoneg = epp->ep_fcntl_autoneg;
320         old_adv_cap = epp->ep_adv_cap_mask;
321
322         epp->ep_fcntl = fcntl;
323         epp->ep_fcntl_autoneg = autoneg;
324
325         /*
326          * Always encode the flow control settings in the advertised
327          * capabilities even if we are not trying to auto-negotiate
328          * them and reconfigure both the PHY and the MAC.
329          */
330         if (fcntl & EFX_FCNTL_RESPOND)
331                 epp->ep_adv_cap_mask |=    (1 << EFX_PHY_CAP_PAUSE |
332                                             1 << EFX_PHY_CAP_ASYM);
333         else
334                 epp->ep_adv_cap_mask &=   ~(1 << EFX_PHY_CAP_PAUSE |
335                                             1 << EFX_PHY_CAP_ASYM);
336
337         if (fcntl & EFX_FCNTL_GENERATE)
338                 epp->ep_adv_cap_mask ^= (1 << EFX_PHY_CAP_ASYM);
339
340         if ((rc = epop->epo_reconfigure(enp)) != 0)
341                 goto fail2;
342
343         if ((rc = emop->emo_reconfigure(enp)) != 0)
344                 goto fail3;
345
346         return (0);
347
348 fail3:
349         EFSYS_PROBE(fail3);
350
351 fail2:
352         EFSYS_PROBE(fail2);
353
354         epp->ep_fcntl = old_fcntl;
355         epp->ep_fcntl_autoneg = old_autoneg;
356         epp->ep_adv_cap_mask = old_adv_cap;
357
358 fail1:
359         EFSYS_PROBE1(fail1, efx_rc_t, rc);
360
361         return (rc);
362 }
363
364                         void
365 efx_mac_fcntl_get(
366         __in            efx_nic_t *enp,
367         __out           unsigned int *fcntl_wantedp,
368         __out           unsigned int *fcntl_linkp)
369 {
370         efx_port_t *epp = &(enp->en_port);
371         unsigned int wanted = 0;
372
373         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
374         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
375
376         /*
377          * Decode the requested flow control settings from the PHY
378          * advertised capabilities.
379          */
380         if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_PAUSE))
381                 wanted = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
382         if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_ASYM))
383                 wanted ^= EFX_FCNTL_GENERATE;
384
385         *fcntl_linkp = epp->ep_fcntl;
386         *fcntl_wantedp = wanted;
387 }
388
389         __checkReturn   efx_rc_t
390 efx_mac_multicast_list_set(
391         __in                            efx_nic_t *enp,
392         __in_ecount(6*count)            uint8_t const *addrs,
393         __in                            int count)
394 {
395         efx_port_t *epp = &(enp->en_port);
396         const efx_mac_ops_t *emop = epp->ep_emop;
397         uint8_t *old_mulcst_addr_list = NULL;
398         uint32_t old_mulcst_addr_count;
399         efx_rc_t rc;
400
401         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
402         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
403
404         if (count > EFX_MAC_MULTICAST_LIST_MAX) {
405                 rc = EINVAL;
406                 goto fail1;
407         }
408
409         old_mulcst_addr_count = epp->ep_mulcst_addr_count;
410         if (old_mulcst_addr_count > 0) {
411                 /* Allocate memory to store old list (instead of using stack) */
412                 EFSYS_KMEM_ALLOC(enp->en_esip,
413                                 old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
414                                 old_mulcst_addr_list);
415                 if (old_mulcst_addr_list == NULL) {
416                         rc = ENOMEM;
417                         goto fail2;
418                 }
419
420                 /* Save the old list in case we need to rollback */
421                 memcpy(old_mulcst_addr_list, epp->ep_mulcst_addr_list,
422                         old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
423         }
424
425         /* Store the new list */
426         memcpy(epp->ep_mulcst_addr_list, addrs,
427                 count * EFX_MAC_ADDR_LEN);
428         epp->ep_mulcst_addr_count = count;
429
430         if ((rc = emop->emo_multicast_list_set(enp)) != 0)
431                 goto fail3;
432
433         if (old_mulcst_addr_count > 0) {
434                 EFSYS_KMEM_FREE(enp->en_esip,
435                                 old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
436                                 old_mulcst_addr_list);
437         }
438
439         return (0);
440
441 fail3:
442         EFSYS_PROBE(fail3);
443
444         /* Restore original list on failure */
445         epp->ep_mulcst_addr_count = old_mulcst_addr_count;
446         if (old_mulcst_addr_count > 0) {
447                 memcpy(epp->ep_mulcst_addr_list, old_mulcst_addr_list,
448                         old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
449
450                 EFSYS_KMEM_FREE(enp->en_esip,
451                                 old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
452                                 old_mulcst_addr_list);
453         }
454
455 fail2:
456         EFSYS_PROBE(fail2);
457
458 fail1:
459         EFSYS_PROBE1(fail1, efx_rc_t, rc);
460
461         return (rc);
462
463 }
464
465         __checkReturn   efx_rc_t
466 efx_mac_filter_default_rxq_set(
467         __in            efx_nic_t *enp,
468         __in            efx_rxq_t *erp,
469         __in            boolean_t using_rss)
470 {
471         efx_port_t *epp = &(enp->en_port);
472         const efx_mac_ops_t *emop = epp->ep_emop;
473         efx_rc_t rc;
474
475         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
476         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
477
478         if (emop->emo_filter_default_rxq_set != NULL) {
479                 rc = emop->emo_filter_default_rxq_set(enp, erp, using_rss);
480                 if (rc != 0)
481                         goto fail1;
482         }
483
484         return (0);
485
486 fail1:
487         EFSYS_PROBE1(fail1, efx_rc_t, rc);
488
489         return (rc);
490 }
491
492                         void
493 efx_mac_filter_default_rxq_clear(
494         __in            efx_nic_t *enp)
495 {
496         efx_port_t *epp = &(enp->en_port);
497         const efx_mac_ops_t *emop = epp->ep_emop;
498
499         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
500         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
501
502         if (emop->emo_filter_default_rxq_clear != NULL)
503                 emop->emo_filter_default_rxq_clear(enp);
504 }
505
506
507 #if EFSYS_OPT_MAC_STATS
508
509 #if EFSYS_OPT_NAMES
510
511 /* START MKCONFIG GENERATED EfxMacStatNamesBlock c11b91b42f922516 */
512 static const char * const __efx_mac_stat_name[] = {
513         "rx_octets",
514         "rx_pkts",
515         "rx_unicst_pkts",
516         "rx_multicst_pkts",
517         "rx_brdcst_pkts",
518         "rx_pause_pkts",
519         "rx_le_64_pkts",
520         "rx_65_to_127_pkts",
521         "rx_128_to_255_pkts",
522         "rx_256_to_511_pkts",
523         "rx_512_to_1023_pkts",
524         "rx_1024_to_15xx_pkts",
525         "rx_ge_15xx_pkts",
526         "rx_errors",
527         "rx_fcs_errors",
528         "rx_drop_events",
529         "rx_false_carrier_errors",
530         "rx_symbol_errors",
531         "rx_align_errors",
532         "rx_internal_errors",
533         "rx_jabber_pkts",
534         "rx_lane0_char_err",
535         "rx_lane1_char_err",
536         "rx_lane2_char_err",
537         "rx_lane3_char_err",
538         "rx_lane0_disp_err",
539         "rx_lane1_disp_err",
540         "rx_lane2_disp_err",
541         "rx_lane3_disp_err",
542         "rx_match_fault",
543         "rx_nodesc_drop_cnt",
544         "tx_octets",
545         "tx_pkts",
546         "tx_unicst_pkts",
547         "tx_multicst_pkts",
548         "tx_brdcst_pkts",
549         "tx_pause_pkts",
550         "tx_le_64_pkts",
551         "tx_65_to_127_pkts",
552         "tx_128_to_255_pkts",
553         "tx_256_to_511_pkts",
554         "tx_512_to_1023_pkts",
555         "tx_1024_to_15xx_pkts",
556         "tx_ge_15xx_pkts",
557         "tx_errors",
558         "tx_sgl_col_pkts",
559         "tx_mult_col_pkts",
560         "tx_ex_col_pkts",
561         "tx_late_col_pkts",
562         "tx_def_pkts",
563         "tx_ex_def_pkts",
564         "pm_trunc_bb_overflow",
565         "pm_discard_bb_overflow",
566         "pm_trunc_vfifo_full",
567         "pm_discard_vfifo_full",
568         "pm_trunc_qbb",
569         "pm_discard_qbb",
570         "pm_discard_mapping",
571         "rxdp_q_disabled_pkts",
572         "rxdp_di_dropped_pkts",
573         "rxdp_streaming_pkts",
574         "rxdp_hlb_fetch",
575         "rxdp_hlb_wait",
576         "vadapter_rx_unicast_packets",
577         "vadapter_rx_unicast_bytes",
578         "vadapter_rx_multicast_packets",
579         "vadapter_rx_multicast_bytes",
580         "vadapter_rx_broadcast_packets",
581         "vadapter_rx_broadcast_bytes",
582         "vadapter_rx_bad_packets",
583         "vadapter_rx_bad_bytes",
584         "vadapter_rx_overflow",
585         "vadapter_tx_unicast_packets",
586         "vadapter_tx_unicast_bytes",
587         "vadapter_tx_multicast_packets",
588         "vadapter_tx_multicast_bytes",
589         "vadapter_tx_broadcast_packets",
590         "vadapter_tx_broadcast_bytes",
591         "vadapter_tx_bad_packets",
592         "vadapter_tx_bad_bytes",
593         "vadapter_tx_overflow",
594 };
595 /* END MKCONFIG GENERATED EfxMacStatNamesBlock */
596
597         __checkReturn                   const char *
598 efx_mac_stat_name(
599         __in                            efx_nic_t *enp,
600         __in                            unsigned int id)
601 {
602         _NOTE(ARGUNUSED(enp))
603         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
604
605         EFSYS_ASSERT3U(id, <, EFX_MAC_NSTATS);
606         return (__efx_mac_stat_name[id]);
607 }
608
609 #endif  /* EFSYS_OPT_NAMES */
610
611 static                                  efx_rc_t
612 efx_mac_stats_mask_add_range(
613         __inout_bcount(mask_size)       uint32_t *maskp,
614         __in                            size_t mask_size,
615         __in                            const struct efx_mac_stats_range *rngp)
616 {
617         unsigned int mask_npages = mask_size / sizeof (*maskp);
618         unsigned int el;
619         unsigned int el_min;
620         unsigned int el_max;
621         unsigned int low;
622         unsigned int high;
623         unsigned int width;
624         efx_rc_t rc;
625
626         if ((mask_npages * EFX_MAC_STATS_MASK_BITS_PER_PAGE) <=
627             (unsigned int)rngp->last) {
628                 rc = EINVAL;
629                 goto fail1;
630         }
631
632         EFSYS_ASSERT3U(rngp->first, <=, rngp->last);
633         EFSYS_ASSERT3U(rngp->last, <, EFX_MAC_NSTATS);
634
635         for (el = 0; el < mask_npages; ++el) {
636                 el_min = el * EFX_MAC_STATS_MASK_BITS_PER_PAGE;
637                 el_max =
638                     el_min + (EFX_MAC_STATS_MASK_BITS_PER_PAGE - 1);
639                 if ((unsigned int)rngp->first > el_max ||
640                     (unsigned int)rngp->last < el_min)
641                         continue;
642                 low = MAX((unsigned int)rngp->first, el_min);
643                 high = MIN((unsigned int)rngp->last, el_max);
644                 width = high - low + 1;
645                 maskp[el] |=
646                     (width == EFX_MAC_STATS_MASK_BITS_PER_PAGE) ?
647                     (~0ULL) : (((1ULL << width) - 1) << (low - el_min));
648         }
649
650         return (0);
651
652 fail1:
653         EFSYS_PROBE1(fail1, efx_rc_t, rc);
654
655         return (rc);
656 }
657
658                                         efx_rc_t
659 efx_mac_stats_mask_add_ranges(
660         __inout_bcount(mask_size)       uint32_t *maskp,
661         __in                            size_t mask_size,
662         __in_ecount(rng_count)          const struct efx_mac_stats_range *rngp,
663         __in                            unsigned int rng_count)
664 {
665         unsigned int i;
666         efx_rc_t rc;
667
668         for (i = 0; i < rng_count; ++i) {
669                 if ((rc = efx_mac_stats_mask_add_range(maskp, mask_size,
670                     &rngp[i])) != 0)
671                         goto fail1;
672         }
673
674         return (0);
675
676 fail1:
677         EFSYS_PROBE1(fail1, efx_rc_t, rc);
678
679         return (rc);
680 }
681
682         __checkReturn                   efx_rc_t
683 efx_mac_stats_get_mask(
684         __in                            efx_nic_t *enp,
685         __out_bcount(mask_size)         uint32_t *maskp,
686         __in                            size_t mask_size)
687 {
688         efx_port_t *epp = &(enp->en_port);
689         const efx_mac_ops_t *emop = epp->ep_emop;
690         efx_rc_t rc;
691
692         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
693         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
694         EFSYS_ASSERT(maskp != NULL);
695         EFSYS_ASSERT(mask_size % sizeof (maskp[0]) == 0);
696
697         (void) memset(maskp, 0, mask_size);
698
699         if ((rc = emop->emo_stats_get_mask(enp, maskp, mask_size)) != 0)
700                 goto fail1;
701
702         return (0);
703
704 fail1:
705         EFSYS_PROBE1(fail1, efx_rc_t, rc);
706
707         return (rc);
708 }
709
710         __checkReturn                   efx_rc_t
711 efx_mac_stats_upload(
712         __in                            efx_nic_t *enp,
713         __in                            efsys_mem_t *esmp)
714 {
715         efx_port_t *epp = &(enp->en_port);
716         const efx_mac_ops_t *emop = epp->ep_emop;
717         efx_rc_t rc;
718
719         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
720         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
721         EFSYS_ASSERT(emop != NULL);
722
723         /*
724          * Don't assert !ep_mac_stats_pending, because the client might
725          * have failed to finalise statistics when previously stopping
726          * the port.
727          */
728         if ((rc = emop->emo_stats_upload(enp, esmp)) != 0)
729                 goto fail1;
730
731         epp->ep_mac_stats_pending = B_TRUE;
732
733         return (0);
734
735 fail1:
736         EFSYS_PROBE1(fail1, efx_rc_t, rc);
737
738         return (rc);
739 }
740
741         __checkReturn                   efx_rc_t
742 efx_mac_stats_periodic(
743         __in                            efx_nic_t *enp,
744         __in                            efsys_mem_t *esmp,
745         __in                            uint16_t period_ms,
746         __in                            boolean_t events)
747 {
748         efx_port_t *epp = &(enp->en_port);
749         const efx_mac_ops_t *emop = epp->ep_emop;
750         efx_rc_t rc;
751
752         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
753         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
754
755         EFSYS_ASSERT(emop != NULL);
756
757         if (emop->emo_stats_periodic == NULL) {
758                 rc = EINVAL;
759                 goto fail1;
760         }
761
762         if ((rc = emop->emo_stats_periodic(enp, esmp, period_ms, events)) != 0)
763                 goto fail2;
764
765         return (0);
766
767 fail2:
768         EFSYS_PROBE(fail2);
769 fail1:
770         EFSYS_PROBE1(fail1, efx_rc_t, rc);
771
772         return (rc);
773 }
774
775
776         __checkReturn                   efx_rc_t
777 efx_mac_stats_update(
778         __in                            efx_nic_t *enp,
779         __in                            efsys_mem_t *esmp,
780         __inout_ecount(EFX_MAC_NSTATS)  efsys_stat_t *essp,
781         __inout_opt                     uint32_t *generationp)
782 {
783         efx_port_t *epp = &(enp->en_port);
784         const efx_mac_ops_t *emop = epp->ep_emop;
785         efx_rc_t rc;
786
787         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
788         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
789         EFSYS_ASSERT(emop != NULL);
790
791         rc = emop->emo_stats_update(enp, esmp, essp, generationp);
792         if (rc == 0)
793                 epp->ep_mac_stats_pending = B_FALSE;
794
795         return (rc);
796 }
797
798 #endif  /* EFSYS_OPT_MAC_STATS */
799
800         __checkReturn                   efx_rc_t
801 efx_mac_select(
802         __in                            efx_nic_t *enp)
803 {
804         efx_port_t *epp = &(enp->en_port);
805         efx_mac_type_t type = EFX_MAC_INVALID;
806         const efx_mac_ops_t *emop;
807         int rc = EINVAL;
808
809         switch (enp->en_family) {
810 #if EFSYS_OPT_SIENA
811         case EFX_FAMILY_SIENA:
812                 emop = &__efx_siena_mac_ops;
813                 type = EFX_MAC_SIENA;
814                 break;
815 #endif /* EFSYS_OPT_SIENA */
816
817 #if EFSYS_OPT_HUNTINGTON
818         case EFX_FAMILY_HUNTINGTON:
819                 emop = &__efx_ef10_mac_ops;
820                 type = EFX_MAC_HUNTINGTON;
821                 break;
822 #endif /* EFSYS_OPT_HUNTINGTON */
823
824 #if EFSYS_OPT_MEDFORD
825         case EFX_FAMILY_MEDFORD:
826                 emop = &__efx_ef10_mac_ops;
827                 type = EFX_MAC_MEDFORD;
828                 break;
829 #endif /* EFSYS_OPT_MEDFORD */
830
831         default:
832                 rc = EINVAL;
833                 goto fail1;
834         }
835
836         EFSYS_ASSERT(type != EFX_MAC_INVALID);
837         EFSYS_ASSERT3U(type, <, EFX_MAC_NTYPES);
838         EFSYS_ASSERT(emop != NULL);
839
840         epp->ep_emop = emop;
841         epp->ep_mac_type = type;
842
843         return (0);
844
845 fail1:
846         EFSYS_PROBE1(fail1, efx_rc_t, rc);
847
848         return (rc);
849 }
850
851
852 #if EFSYS_OPT_SIENA
853
854 #define EFX_MAC_HASH_BITS       (1 << 8)
855
856 /* Compute the multicast hash as used on Falcon and Siena. */
857 static  void
858 siena_mac_multicast_hash_compute(
859         __in_ecount(6*count)            uint8_t const *addrs,
860         __in                            int count,
861         __out                           efx_oword_t *hash_low,
862         __out                           efx_oword_t *hash_high)
863 {
864         uint32_t crc, index;
865         int i;
866
867         EFSYS_ASSERT(hash_low != NULL);
868         EFSYS_ASSERT(hash_high != NULL);
869
870         EFX_ZERO_OWORD(*hash_low);
871         EFX_ZERO_OWORD(*hash_high);
872
873         for (i = 0; i < count; i++) {
874                 /* Calculate hash bucket (IEEE 802.3 CRC32 of the MAC addr) */
875                 crc = efx_crc32_calculate(0xffffffff, addrs, EFX_MAC_ADDR_LEN);
876                 index = crc % EFX_MAC_HASH_BITS;
877                 if (index < 128) {
878                         EFX_SET_OWORD_BIT(*hash_low, index);
879                 } else {
880                         EFX_SET_OWORD_BIT(*hash_high, index - 128);
881                 }
882
883                 addrs += EFX_MAC_ADDR_LEN;
884         }
885 }
886
887 static  __checkReturn   efx_rc_t
888 siena_mac_multicast_list_set(
889         __in            efx_nic_t *enp)
890 {
891         efx_port_t *epp = &(enp->en_port);
892         const efx_mac_ops_t *emop = epp->ep_emop;
893         efx_oword_t old_hash[2];
894         efx_rc_t rc;
895
896         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
897         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
898
899         memcpy(old_hash, epp->ep_multicst_hash, sizeof (old_hash));
900
901         siena_mac_multicast_hash_compute(
902             epp->ep_mulcst_addr_list,
903             epp->ep_mulcst_addr_count,
904             &epp->ep_multicst_hash[0],
905             &epp->ep_multicst_hash[1]);
906
907         if ((rc = emop->emo_reconfigure(enp)) != 0)
908                 goto fail1;
909
910         return (0);
911
912 fail1:
913         EFSYS_PROBE1(fail1, efx_rc_t, rc);
914
915         memcpy(epp->ep_multicst_hash, old_hash, sizeof (old_hash));
916
917         return (rc);
918 }
919
920 #endif /* EFSYS_OPT_SIENA */