1 /*
   2  * Copyright (c) 2008-2015 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 /*
  32  * All efx_mac_*() must be after efx_port_init()
  33  * LOCKING STRATEGY: Aquire sm_lock and test sm_state==SFXGE_MAC_STARTED
  34  * to serialise against sfxge_restart()
  35  */
  36 
  37 #include <sys/types.h>
  38 #include <sys/sysmacros.h>
  39 #include <sys/ddi.h>
  40 #include <sys/sunddi.h>
  41 
  42 #include "sfxge.h"
  43 #include "efx.h"
  44 
  45 #define SFXGE_MAC_POLL_PERIOD_MS 1000
  46 
  47 static void sfxge_mac_link_update_locked(sfxge_t *sp, efx_link_mode_t mode);
  48 
  49 
  50 /* MAC DMA attributes */
  51 static ddi_device_acc_attr_t sfxge_mac_devacc = {
  52 
  53         DDI_DEVICE_ATTR_V0,     /* devacc_attr_version */
  54         DDI_NEVERSWAP_ACC,      /* devacc_attr_endian_flags */
  55         DDI_STRICTORDER_ACC     /* devacc_attr_dataorder */
  56 };
  57 
  58 static ddi_dma_attr_t sfxge_mac_dma_attr = {
  59         DMA_ATTR_V0,            /* dma_attr_version     */
  60         0,                      /* dma_attr_addr_lo     */
  61         0xffffffffffffffffull,  /* dma_attr_addr_hi     */
  62         0xffffffffffffffffull,  /* dma_attr_count_max   */
  63         0x1000,                 /* dma_attr_align       */
  64         0xffffffff,             /* dma_attr_burstsizes  */
  65         1,                      /* dma_attr_minxfer     */
  66         0xffffffffffffffffull,  /* dma_attr_maxxfer     */
  67         0xffffffffffffffffull,  /* dma_attr_seg         */
  68         1,                      /* dma_attr_sgllen      */
  69         1,                      /* dma_attr_granular    */
  70         0                       /* dma_attr_flags       */
  71 };
  72 
  73 
  74 static void
  75 _sfxge_mac_stat_update(sfxge_mac_t *smp, int tries, int delay_usec)
  76 {
  77         sfxge_t *sp = smp->sm_sp;
  78         efsys_mem_t *esmp = &(smp->sm_mem);
  79         int i;
  80 
  81         ASSERT(mutex_owned(&(smp->sm_lock)));
  82         ASSERT3U(smp->sm_state, !=, SFXGE_MAC_UNINITIALIZED);
  83 
  84         /* if no stats pending then they are already freshly updated */
  85         if (smp->sm_mac_stats_timer_reqd && !smp->sm_mac_stats_pend)
  86                 return;
  87 
  88         for (i = 0; i < tries; i++) {
  89                 /* Try to update the cached counters */
  90                 if (efx_mac_stats_update(sp->s_enp, esmp, smp->sm_stat,
  91                     NULL) != EAGAIN)
  92                         goto done;
  93 
  94                 drv_usecwait(delay_usec);
  95         }
  96 
  97         DTRACE_PROBE(mac_stat_timeout);
  98         dev_err(sp->s_dip, CE_NOTE, SFXGE_CMN_ERR "MAC stats timeout");
  99         return;
 100 
 101 done:
 102         smp->sm_mac_stats_pend = B_FALSE;
 103         smp->sm_lbolt = ddi_get_lbolt();
 104 }
 105 
 106 static void
 107 sfxge_mac_stat_update_quick(sfxge_mac_t *smp)
 108 {
 109         /*
 110          * Update the statistics from the most recent DMA. This might race
 111          * with an inflight dma, so retry once. Otherwise get mac stat
 112          * values from the last mac_poll() or MC periodic stats.
 113          */
 114         _sfxge_mac_stat_update(smp, 2, 50);
 115 }
 116 
 117 static void
 118 sfxge_mac_stat_update_wait(sfxge_mac_t *smp)
 119 {
 120         /* Wait a max of 20 * 500us = 10ms */
 121         _sfxge_mac_stat_update(smp, 20, 500);
 122 }
 123 
 124 static int
 125 sfxge_mac_kstat_update(kstat_t *ksp, int rw)
 126 {
 127         sfxge_mac_t *smp = ksp->ks_private;
 128         kstat_named_t *knp;
 129         int rc;
 130         unsigned int val;
 131         sfxge_rx_coalesce_mode_t rxmode;
 132 
 133         if (rw != KSTAT_READ) {
 134                 rc = EACCES;
 135                 goto fail1;
 136         }
 137 
 138         ASSERT(mutex_owned(&(smp->sm_lock)));
 139 
 140         if (smp->sm_state != SFXGE_MAC_STARTED)
 141                 goto done;
 142 
 143         sfxge_mac_stat_update_quick(smp);
 144 
 145         knp = smp->sm_stat;
 146         knp += EFX_MAC_NSTATS;
 147 
 148         knp->value.ui64 = (smp->sm_link_up) ? 1 : 0;
 149         knp++;
 150 
 151         knp->value.ui64 = smp->sm_link_speed;
 152         knp++;
 153 
 154         knp->value.ui64 = smp->sm_link_duplex;
 155         knp++;
 156 
 157         knp->value.ui64 = (smp->sm_fcntl & EFX_FCNTL_GENERATE) ? 1 : 0;
 158         knp++;
 159 
 160         knp->value.ui64 = (smp->sm_fcntl & EFX_FCNTL_RESPOND) ? 1 : 0;
 161         knp++;
 162 
 163         sfxge_ev_moderation_get(smp->sm_sp, &val);
 164         knp->value.ui64 = val;
 165         knp++;
 166 
 167         sfxge_rx_coalesce_mode_get(smp->sm_sp, &rxmode);
 168         knp->value.ui64 = (uint64_t)rxmode;
 169         knp++;
 170 
 171         if (sfxge_rx_scale_count_get(smp->sm_sp, &val) != 0)
 172                 val = 0;
 173         knp->value.ui64 = val;
 174         knp++;
 175 
 176 done:
 177         return (0);
 178 
 179 fail1:
 180         DTRACE_PROBE1(fail1, int, rc);
 181 
 182         return (rc);
 183 }
 184 
 185 static int
 186 sfxge_mac_kstat_init(sfxge_t *sp)
 187 {
 188         sfxge_mac_t *smp = &(sp->s_mac);
 189         dev_info_t *dip = sp->s_dip;
 190         char name[MAXNAMELEN];
 191         kstat_t *ksp;
 192         kstat_named_t *knp;
 193         unsigned int id;
 194         int rc;
 195 
 196         /* Create the set */
 197         (void) snprintf(name, MAXNAMELEN - 1, "%s_mac", ddi_driver_name(dip));
 198 
 199         if ((ksp = kstat_create((char *)ddi_driver_name(dip),
 200             ddi_get_instance(dip), name, "mac", KSTAT_TYPE_NAMED,
 201             EFX_MAC_NSTATS + 8, 0)) == NULL) {
 202                 rc = ENOMEM;
 203                 goto fail1;
 204         }
 205 
 206         smp->sm_ksp = ksp;
 207 
 208         ksp->ks_update = sfxge_mac_kstat_update;
 209         ksp->ks_private = smp;
 210         ksp->ks_lock = &(smp->sm_lock);
 211 
 212         /* Initialise the named stats */
 213         smp->sm_stat = knp = ksp->ks_data;
 214         for (id = 0; id < EFX_MAC_NSTATS; id++) {
 215                 kstat_named_init(knp, (char *)efx_mac_stat_name(sp->s_enp, id),
 216                     KSTAT_DATA_UINT64);
 217                 knp++;
 218         }
 219 
 220         kstat_named_init(knp++, "link_up", KSTAT_DATA_UINT64);
 221         kstat_named_init(knp++, "link_speed", KSTAT_DATA_UINT64);
 222         kstat_named_init(knp++, "link_duplex", KSTAT_DATA_UINT64);
 223         kstat_named_init(knp++, "fcntl_generate", KSTAT_DATA_UINT64);
 224         kstat_named_init(knp++, "fcntl_respond", KSTAT_DATA_UINT64);
 225         kstat_named_init(knp++, "intr_moderation", KSTAT_DATA_UINT64);
 226         kstat_named_init(knp++, "rx_coalesce_mode", KSTAT_DATA_UINT64);
 227         kstat_named_init(knp++, "rx_scale_count", KSTAT_DATA_UINT64);
 228 
 229         kstat_install(ksp);
 230 
 231         return (0);
 232 
 233 fail1:
 234         DTRACE_PROBE1(fail1, int, rc);
 235 
 236         return (rc);
 237 }
 238 
 239 static void
 240 sfxge_mac_kstat_fini(sfxge_t *sp)
 241 {
 242         sfxge_mac_t *smp = &(sp->s_mac);
 243 
 244         /* Destroy the set */
 245         kstat_delete(smp->sm_ksp);
 246         smp->sm_ksp = NULL;
 247         smp->sm_stat = NULL;
 248 }
 249 
 250 void
 251 sfxge_mac_stat_get(sfxge_t *sp, unsigned int id, uint64_t *valp)
 252 {
 253         sfxge_mac_t *smp = &(sp->s_mac);
 254 
 255         /* Make sure the cached counter values are recent */
 256         mutex_enter(&(smp->sm_lock));
 257 
 258         if (smp->sm_state != SFXGE_MAC_STARTED)
 259                 goto done;
 260 
 261         sfxge_mac_stat_update_quick(smp);
 262 
 263         *valp = smp->sm_stat[id].value.ui64;
 264 
 265 done:
 266         mutex_exit(&(smp->sm_lock));
 267 }
 268 
 269 static void
 270 sfxge_mac_poll(void *arg)
 271 {
 272         sfxge_t *sp = arg;
 273         efx_nic_t *enp = sp->s_enp;
 274         sfxge_mac_t *smp = &(sp->s_mac);
 275         efsys_mem_t *esmp = &(smp->sm_mem);
 276         efx_link_mode_t mode;
 277         clock_t timeout;
 278 
 279         mutex_enter(&(smp->sm_lock));
 280         while (smp->sm_state == SFXGE_MAC_STARTED) {
 281 
 282                 /* clears smp->sm_mac_stats_pend if appropriate */
 283                 if (smp->sm_mac_stats_pend)
 284                         sfxge_mac_stat_update_wait(smp);
 285 
 286                 /* This may sleep waiting for MCDI completion */
 287                 mode = EFX_LINK_UNKNOWN;
 288                 if (efx_port_poll(enp, &mode) == 0)
 289                         sfxge_mac_link_update_locked(sp, mode);
 290 
 291                 if ((smp->sm_link_poll_reqd == B_FALSE) &&
 292                     (smp->sm_mac_stats_timer_reqd == B_FALSE))
 293                         goto done;
 294 
 295                 /* Zero the memory */
 296                 bzero(esmp->esm_base, EFX_MAC_STATS_SIZE);
 297 
 298                 /* Trigger upload the MAC statistics counters */
 299                 if (smp->sm_link_up &&
 300                     efx_mac_stats_upload(sp->s_enp, esmp) == 0)
 301                         smp->sm_mac_stats_pend = B_TRUE;
 302 
 303                 /* Wait for timeout or end of polling */
 304                 timeout = ddi_get_lbolt() + drv_usectohz(1000 *
 305                     SFXGE_MAC_POLL_PERIOD_MS);
 306                 while (smp->sm_state == SFXGE_MAC_STARTED) {
 307                         if (cv_timedwait(&(smp->sm_link_poll_kv),
 308                             &(smp->sm_lock), timeout) < 0) {
 309                                 /* Timeout - poll if polling still enabled */
 310                                 break;
 311                         }
 312                 }
 313         }
 314 done:
 315         mutex_exit(&(smp->sm_lock));
 316 
 317 }
 318 
 319 static void
 320 sfxge_mac_poll_start(sfxge_t *sp)
 321 {
 322         sfxge_mac_t *smp = &(sp->s_mac);
 323 
 324         ASSERT(mutex_owned(&(smp->sm_lock)));
 325         ASSERT3U(smp->sm_state, ==, SFXGE_MAC_STARTED);
 326 
 327         /* Schedule a poll */
 328         (void) ddi_taskq_dispatch(smp->sm_tqp, sfxge_mac_poll, sp, DDI_SLEEP);
 329 }
 330 
 331 static void
 332 sfxge_mac_poll_stop(sfxge_t *sp)
 333 {
 334         sfxge_mac_t *smp = &(sp->s_mac);
 335 
 336         ASSERT(mutex_owned(&(smp->sm_lock)));
 337         ASSERT3U(smp->sm_state, ==, SFXGE_MAC_INITIALIZED);
 338 
 339         cv_broadcast(&(smp->sm_link_poll_kv));
 340 
 341         /* Wait for link polling to cease */
 342         mutex_exit(&(smp->sm_lock));
 343         ddi_taskq_wait(smp->sm_tqp);
 344         mutex_enter(&(smp->sm_lock));
 345 
 346         /* Wait for any pending DMAed stats to complete */
 347         sfxge_mac_stat_update_wait(smp);
 348 }
 349 
 350 int
 351 sfxge_mac_init(sfxge_t *sp)
 352 {
 353         sfxge_mac_t *smp = &(sp->s_mac);
 354         efsys_mem_t *esmp = &(smp->sm_mem);
 355         dev_info_t *dip = sp->s_dip;
 356         sfxge_dma_buffer_attr_t dma_attr;
 357         const efx_nic_cfg_t *encp;
 358         unsigned char *bytes;
 359         unsigned int n;
 360         int err, rc;
 361 
 362         SFXGE_OBJ_CHECK(smp, sfxge_mac_t);
 363 
 364         ASSERT3U(smp->sm_state, ==, SFXGE_MAC_UNINITIALIZED);
 365 
 366         smp->sm_sp = sp;
 367         encp = efx_nic_cfg_get(sp->s_enp);
 368         smp->sm_link_poll_reqd = (~encp->enc_features &
 369             EFX_FEATURE_LINK_EVENTS);
 370         smp->sm_mac_stats_timer_reqd = (~encp->enc_features &
 371             EFX_FEATURE_PERIODIC_MAC_STATS);
 372 
 373         mutex_init(&(smp->sm_lock), NULL, MUTEX_DRIVER,
 374             DDI_INTR_PRI(sp->s_intr.si_intr_pri));
 375         cv_init(&(smp->sm_link_poll_kv), NULL, CV_DRIVER, NULL);
 376 
 377         /* Create link poll taskq */
 378         smp->sm_tqp = ddi_taskq_create(dip, "mac_tq", 1, TASKQ_DEFAULTPRI, 0);
 379         if (smp->sm_tqp == NULL) {
 380                 rc = ENOMEM;
 381                 goto fail1;
 382         }
 383 
 384         if ((rc = sfxge_phy_init(sp)) != 0)
 385                 goto fail2;
 386 
 387         dma_attr.sdba_dip        = dip;
 388         dma_attr.sdba_dattrp     = &sfxge_mac_dma_attr;
 389         dma_attr.sdba_callback   = DDI_DMA_SLEEP;
 390         dma_attr.sdba_length     = EFX_MAC_STATS_SIZE;
 391         dma_attr.sdba_memflags   = DDI_DMA_CONSISTENT;
 392         dma_attr.sdba_devaccp    = &sfxge_mac_devacc;
 393         dma_attr.sdba_bindflags  = DDI_DMA_READ | DDI_DMA_CONSISTENT;
 394         dma_attr.sdba_maxcookies = 1;
 395         dma_attr.sdba_zeroinit   = B_TRUE;
 396 
 397         if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
 398                 goto fail3;
 399 
 400         /* Set the initial flow control values */
 401         smp->sm_fcntl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
 402 
 403         /*
 404          * Determine the 'burnt-in' MAC address:
 405          *
 406          * A: if the "mac-address" property is set on our device node use that.
 407          * B: otherwise, use the value from NVRAM.
 408          */
 409 
 410         /* A: property  */
 411         err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
 412             "mac-address", &bytes, &n);
 413         switch (err) {
 414         case DDI_PROP_SUCCESS:
 415                 if (n == ETHERADDRL) {
 416                         bcopy(bytes, smp->sm_bia, ETHERADDRL);
 417                         goto done;
 418                 }
 419 
 420                 ddi_prop_free(bytes);
 421                 break;
 422 
 423         default:
 424                 break;
 425         }
 426 
 427         /* B: NVRAM */
 428         bcopy(encp->enc_mac_addr, smp->sm_bia, ETHERADDRL);
 429 
 430 done:
 431         /* Initialize the statistics */
 432         if ((rc = sfxge_mac_kstat_init(sp)) != 0)
 433                 goto fail4;
 434 
 435         if ((rc = sfxge_phy_kstat_init(sp)) != 0)
 436                 goto fail5;
 437 
 438         smp->sm_state = SFXGE_MAC_INITIALIZED;
 439 
 440         return (0);
 441 
 442 fail5:
 443         DTRACE_PROBE(fail5);
 444 
 445         sfxge_mac_kstat_fini(sp);
 446 fail4:
 447         DTRACE_PROBE(fail4);
 448 
 449         /* Tear down DMA setup */
 450         sfxge_dma_buffer_destroy(esmp);
 451 fail3:
 452         DTRACE_PROBE(fail3);
 453 
 454         sfxge_phy_fini(sp);
 455 fail2:
 456         DTRACE_PROBE(fail2);
 457 
 458         /* Destroy the link poll taskq */
 459         ddi_taskq_destroy(smp->sm_tqp);
 460         smp->sm_tqp = NULL;
 461 
 462 fail1:
 463         DTRACE_PROBE1(fail1, int, rc);
 464 
 465         cv_destroy(&(smp->sm_link_poll_kv));
 466 
 467         mutex_destroy(&(smp->sm_lock));
 468 
 469         smp->sm_sp = NULL;
 470 
 471         SFXGE_OBJ_CHECK(smp, sfxge_mac_t);
 472 
 473         return (rc);
 474 }
 475 
 476 static int
 477 sfxge_mac_filter_apply(sfxge_t *sp)
 478 {
 479         efx_nic_t *enp = sp->s_enp;
 480         sfxge_mac_t *smp = &(sp->s_mac);
 481         int rc;
 482 
 483         ASSERT(mutex_owned(&(smp->sm_lock)));
 484 
 485         if (smp->sm_state == SFXGE_MAC_STARTED) {
 486                 boolean_t all_unicst;
 487                 boolean_t mulcst;
 488                 boolean_t all_mulcst;
 489                 boolean_t brdcst;
 490 
 491                 all_unicst = (smp->sm_promisc == SFXGE_PROMISC_ALL_PHYS);
 492                 mulcst = (smp->sm_mcast_count > 0);
 493                 all_mulcst = (smp->sm_promisc >= SFXGE_PROMISC_ALL_MULTI);
 494                 brdcst = B_TRUE;
 495 
 496                 if ((rc = efx_mac_filter_set(enp, all_unicst, mulcst,
 497                     all_mulcst, brdcst)) != 0) {
 498                         goto fail1;
 499                 }
 500                 if ((rc = efx_mac_multicast_list_set(enp,
 501                     smp->sm_mcast_addr, smp->sm_mcast_count)) != 0)
 502                         goto fail2;
 503         }
 504 
 505         return (0);
 506 
 507 fail2:
 508         DTRACE_PROBE(fail2);
 509 fail1:
 510         DTRACE_PROBE1(fail1, int, rc);
 511 
 512         return (rc);
 513 }
 514 
 515 int
 516 sfxge_mac_start(sfxge_t *sp, boolean_t restart)
 517 {
 518         sfxge_mac_t *smp = &(sp->s_mac);
 519         efsys_mem_t *esmp = &(smp->sm_mem);
 520         efx_nic_t *enp = sp->s_enp;
 521         size_t pdu;
 522         int rc;
 523 
 524         mutex_enter(&(smp->sm_lock));
 525 
 526         ASSERT3U(smp->sm_state, ==, SFXGE_MAC_INITIALIZED);
 527 
 528         if ((rc = efx_port_init(enp)) != 0)
 529                 goto fail1;
 530 
 531         /*
 532          * Set up the advertised capabilities that may have been asked for
 533          * before the call to efx_port_init().
 534          */
 535         if ((rc = sfxge_phy_cap_apply(sp, !restart)) != 0)
 536                 goto fail2;
 537 
 538         /* Set the SDU */
 539         pdu = EFX_MAC_PDU(sp->s_mtu);
 540         if ((rc = efx_mac_pdu_set(enp, pdu)) != 0)
 541                 goto fail3;
 542 
 543         if ((rc = efx_mac_fcntl_set(enp, smp->sm_fcntl, B_TRUE)) != 0)
 544                 goto fail4;
 545 
 546         /* Set the unicast address */
 547         if ((rc = efx_mac_addr_set(enp, (smp->sm_laa_valid) ?
 548             smp->sm_laa : smp->sm_bia)) != 0)
 549                 goto fail5;
 550 
 551         if ((rc = sfxge_mac_filter_apply(sp)) != 0)
 552                 goto fail6;
 553 
 554         if (!smp->sm_mac_stats_timer_reqd) {
 555                 if ((rc = efx_mac_stats_periodic(enp, esmp,
 556                     SFXGE_MAC_POLL_PERIOD_MS, B_FALSE)) != 0)
 557                         goto fail7;
 558         }
 559 
 560         if ((rc = efx_mac_drain(enp, B_FALSE)) != 0)
 561                 goto fail8;
 562 
 563         smp->sm_state = SFXGE_MAC_STARTED;
 564 
 565         /*
 566          * Start link state polling. For hardware that reports link change
 567          * events we still poll once to update the initial link state.
 568          */
 569         sfxge_mac_poll_start(sp);
 570 
 571         mutex_exit(&(smp->sm_lock));
 572         return (0);
 573 
 574 fail8:
 575         DTRACE_PROBE(fail8);
 576         (void) efx_mac_stats_periodic(enp, esmp, 0, B_FALSE);
 577 fail7:
 578         DTRACE_PROBE(fail7);
 579 fail6:
 580         DTRACE_PROBE(fail6);
 581 fail5:
 582         DTRACE_PROBE(fail5);
 583 fail4:
 584         DTRACE_PROBE(fail4);
 585 fail3:
 586         DTRACE_PROBE(fail3);
 587 fail2:
 588         DTRACE_PROBE(fail2);
 589         efx_port_fini(enp);
 590 fail1:
 591         DTRACE_PROBE1(fail1, int, rc);
 592 
 593         mutex_exit(&(smp->sm_lock));
 594 
 595         return (rc);
 596 }
 597 
 598 
 599 static void
 600 sfxge_mac_link_update_locked(sfxge_t *sp, efx_link_mode_t mode)
 601 {
 602         sfxge_mac_t *smp = &(sp->s_mac);
 603         const char *change, *duplex;
 604         char info[sizeof (": now 10000Mbps FULL duplex")];
 605 
 606         ASSERT(mutex_owned(&(smp->sm_lock)));
 607         if (smp->sm_state != SFXGE_MAC_STARTED)
 608                 return;
 609 
 610         if (smp->sm_link_mode == mode)
 611                 return;
 612 
 613         smp->sm_link_mode = mode;
 614         smp->sm_link_up = B_TRUE;
 615 
 616         switch (smp->sm_link_mode) {
 617         case EFX_LINK_UNKNOWN:
 618         case EFX_LINK_DOWN:
 619                 smp->sm_link_speed = 0;
 620                 smp->sm_link_duplex = SFXGE_LINK_DUPLEX_UNKNOWN;
 621                 smp->sm_link_up = B_FALSE;
 622                 break;
 623 
 624         case EFX_LINK_10HDX:
 625         case EFX_LINK_10FDX:
 626                 smp->sm_link_speed = 10;
 627                 smp->sm_link_duplex = (smp->sm_link_mode == EFX_LINK_10HDX) ?
 628                     SFXGE_LINK_DUPLEX_HALF : SFXGE_LINK_DUPLEX_FULL;
 629                 break;
 630 
 631         case EFX_LINK_100HDX:
 632         case EFX_LINK_100FDX:
 633                 smp->sm_link_speed = 100;
 634                 smp->sm_link_duplex = (smp->sm_link_mode == EFX_LINK_100HDX) ?
 635                     SFXGE_LINK_DUPLEX_HALF : SFXGE_LINK_DUPLEX_FULL;
 636                 break;
 637 
 638         case EFX_LINK_1000HDX:
 639         case EFX_LINK_1000FDX:
 640                 smp->sm_link_speed = 1000;
 641                 smp->sm_link_duplex = (smp->sm_link_mode == EFX_LINK_1000HDX) ?
 642                     SFXGE_LINK_DUPLEX_HALF : SFXGE_LINK_DUPLEX_FULL;
 643                 break;
 644 
 645         case EFX_LINK_10000FDX:
 646                 smp->sm_link_speed = 10000;
 647                 smp->sm_link_duplex = SFXGE_LINK_DUPLEX_FULL;
 648                 break;
 649 
 650         case EFX_LINK_40000FDX:
 651                 smp->sm_link_speed = 40000;
 652                 smp->sm_link_duplex = SFXGE_LINK_DUPLEX_FULL;
 653                 break;
 654 
 655         default:
 656                 ASSERT(B_FALSE);
 657                 break;
 658         }
 659 
 660         duplex = (smp->sm_link_duplex == SFXGE_LINK_DUPLEX_FULL) ?
 661             "full" : "half";
 662         change = (smp->sm_link_up) ? "UP" : "DOWN";
 663         (void) snprintf(info, sizeof (info), ": now %dMbps %s duplex",
 664             smp->sm_link_speed, duplex);
 665 
 666         dev_err(sp->s_dip, CE_NOTE, SFXGE_CMN_ERR "Link %s%s",
 667             change, smp->sm_link_up ? info : "");
 668 
 669         /* Push link state update to the OS */
 670         sfxge_gld_link_update(sp);
 671 }
 672 
 673 void
 674 sfxge_mac_link_update(sfxge_t *sp, efx_link_mode_t mode)
 675 {
 676         sfxge_mac_t *smp = &(sp->s_mac);
 677 
 678         mutex_enter(&(smp->sm_lock));
 679         sfxge_mac_link_update_locked(sp, mode);
 680         mutex_exit(&(smp->sm_lock));
 681 }
 682 
 683 void
 684 sfxge_mac_link_check(sfxge_t *sp, boolean_t *upp)
 685 {
 686         sfxge_mac_t *smp = &(sp->s_mac);
 687 
 688         mutex_enter(&(smp->sm_lock));
 689         *upp = smp->sm_link_up;
 690         mutex_exit(&(smp->sm_lock));
 691 }
 692 
 693 void
 694 sfxge_mac_link_speed_get(sfxge_t *sp, unsigned int *speedp)
 695 {
 696         sfxge_mac_t *smp = &(sp->s_mac);
 697 
 698         mutex_enter(&(smp->sm_lock));
 699         *speedp = smp->sm_link_speed;
 700         mutex_exit(&(smp->sm_lock));
 701 }
 702 
 703 void
 704 sfxge_mac_link_duplex_get(sfxge_t *sp, sfxge_link_duplex_t *duplexp)
 705 {
 706         sfxge_mac_t *smp = &(sp->s_mac);
 707 
 708         mutex_enter(&(smp->sm_lock));
 709         *duplexp = smp->sm_link_duplex;
 710         mutex_exit(&(smp->sm_lock));
 711 }
 712 
 713 void
 714 sfxge_mac_fcntl_get(sfxge_t *sp, unsigned int *fcntlp)
 715 {
 716         sfxge_mac_t *smp = &(sp->s_mac);
 717 
 718         mutex_enter(&(smp->sm_lock));
 719         *fcntlp = smp->sm_fcntl;
 720         mutex_exit(&(smp->sm_lock));
 721 }
 722 
 723 int
 724 sfxge_mac_fcntl_set(sfxge_t *sp, unsigned int fcntl)
 725 {
 726         sfxge_mac_t *smp = &(sp->s_mac);
 727         int rc;
 728 
 729         mutex_enter(&(smp->sm_lock));
 730 
 731         if (smp->sm_fcntl == fcntl)
 732                 goto done;
 733 
 734         smp->sm_fcntl = fcntl;
 735 
 736         if (smp->sm_state != SFXGE_MAC_STARTED)
 737                 goto done;
 738 
 739         if ((rc = efx_mac_fcntl_set(sp->s_enp, smp->sm_fcntl, B_TRUE)) != 0)
 740                 goto fail1;
 741 
 742 done:
 743         mutex_exit(&(smp->sm_lock));
 744 
 745         return (0);
 746 
 747 fail1:
 748         DTRACE_PROBE1(fail1, int, rc);
 749 
 750         mutex_exit(&(smp->sm_lock));
 751 
 752         return (rc);
 753 }
 754 
 755 int
 756 sfxge_mac_unicst_get(sfxge_t *sp, sfxge_unicst_type_t type, uint8_t *addr)
 757 {
 758         sfxge_mac_t *smp = &(sp->s_mac);
 759         int rc;
 760 
 761         if (type >= SFXGE_UNICST_NTYPES) {
 762                 rc = EINVAL;
 763                 goto fail1;
 764         }
 765 
 766         mutex_enter(&(smp->sm_lock));
 767 
 768         if (smp->sm_state != SFXGE_MAC_INITIALIZED &&
 769             smp->sm_state != SFXGE_MAC_STARTED) {
 770                 rc = EFAULT;
 771                 goto fail2;
 772         }
 773 
 774         switch (type) {
 775         case SFXGE_UNICST_BIA:
 776                 bcopy(smp->sm_bia, addr, ETHERADDRL);
 777                 break;
 778 
 779         case SFXGE_UNICST_LAA:
 780                 if (!(smp->sm_laa_valid)) {
 781                         rc = ENOENT;
 782                         goto fail3;
 783                 }
 784 
 785                 bcopy(smp->sm_laa, addr, ETHERADDRL);
 786                 break;
 787 
 788         default:
 789                 ASSERT(B_FALSE);
 790                 break;
 791         }
 792 
 793         mutex_exit(&(smp->sm_lock));
 794 
 795         return (0);
 796 
 797 
 798 fail3:
 799         DTRACE_PROBE(fail3);
 800 fail2:
 801         DTRACE_PROBE(fail2);
 802 
 803         mutex_exit(&(smp->sm_lock));
 804 
 805 fail1:
 806         DTRACE_PROBE1(fail1, int, rc);
 807 
 808         return (rc);
 809 }
 810 
 811 int
 812 sfxge_mac_unicst_set(sfxge_t *sp, uint8_t *addr)
 813 {
 814         sfxge_mac_t *smp = &(sp->s_mac);
 815         efx_nic_t *enp = sp->s_enp;
 816         int rc;
 817 
 818         mutex_enter(&(smp->sm_lock));
 819 
 820         bcopy(addr, smp->sm_laa, ETHERADDRL);
 821         smp->sm_laa_valid = B_TRUE;
 822 
 823         if (smp->sm_state != SFXGE_MAC_STARTED)
 824                 goto done;
 825 
 826         if ((rc = efx_mac_addr_set(enp, smp->sm_laa)) != 0)
 827                 goto fail1;
 828 
 829 done:
 830         mutex_exit(&(smp->sm_lock));
 831 
 832         return (0);
 833 
 834 fail1:
 835         DTRACE_PROBE1(fail1, int, rc);
 836 
 837         mutex_exit(&(smp->sm_lock));
 838 
 839         return (rc);
 840 }
 841 
 842 int
 843 sfxge_mac_promisc_set(sfxge_t *sp, sfxge_promisc_type_t promisc)
 844 {
 845         sfxge_mac_t *smp = &(sp->s_mac);
 846         int rc;
 847 
 848         mutex_enter(&(smp->sm_lock));
 849 
 850         if (smp->sm_promisc == promisc)
 851                 goto done;
 852 
 853         smp->sm_promisc = promisc;
 854 
 855         if ((rc = sfxge_mac_filter_apply(sp)) != 0)
 856                 goto fail1;
 857 
 858 done:
 859         mutex_exit(&(smp->sm_lock));
 860         return (0);
 861 
 862 fail1:
 863         DTRACE_PROBE1(fail1, int, rc);
 864         mutex_exit(&(smp->sm_lock));
 865 
 866         return (rc);
 867 }
 868 
 869 int
 870 sfxge_mac_multicst_add(sfxge_t *sp, const uint8_t *addr)
 871 {
 872         sfxge_mac_t *smp = &(sp->s_mac);
 873         int i;
 874         int rc;
 875 
 876         mutex_enter(&(smp->sm_lock));
 877 
 878         /* Check if the address is already in the list */
 879         i = 0;
 880         while (i < smp->sm_mcast_count) {
 881                 if (bcmp(smp->sm_mcast_addr + (i * ETHERADDRL),
 882                     addr, ETHERADDRL) == 0)
 883                         goto done;
 884                 else
 885                         i++;
 886         }
 887 
 888         /* Add to the list */
 889         bcopy(addr, smp->sm_mcast_addr + (smp->sm_mcast_count++ * ETHERADDRL),
 890             ETHERADDRL);
 891 
 892         if ((rc = sfxge_mac_filter_apply(sp)) != 0)
 893                 goto fail1;
 894 
 895 done:
 896         mutex_exit(&(smp->sm_lock));
 897         return (0);
 898 
 899 fail1:
 900         DTRACE_PROBE1(fail1, int, rc);
 901         mutex_exit(&(smp->sm_lock));
 902 
 903         return (rc);
 904 }
 905 
 906 int
 907 sfxge_mac_multicst_remove(sfxge_t *sp, const uint8_t *addr)
 908 {
 909         sfxge_mac_t *smp = &(sp->s_mac);
 910         int i;
 911         int rc;
 912 
 913         mutex_enter(&(smp->sm_lock));
 914 
 915         i = 0;
 916         while (i < smp->sm_mcast_count) {
 917                 if (bcmp(smp->sm_mcast_addr + (i * ETHERADDRL),
 918                     addr, ETHERADDRL) == 0) {
 919                         (void) memmove(smp->sm_mcast_addr + (i * ETHERADDRL),
 920                             smp->sm_mcast_addr + ((i + 1) * ETHERADDRL),
 921                             (smp->sm_mcast_count - (i + 1)) * ETHERADDRL);
 922                         smp->sm_mcast_count--;
 923                 } else
 924                         i++;
 925         }
 926 
 927         if ((rc = sfxge_mac_filter_apply(sp)) != 0)
 928                 goto fail1;
 929 
 930         mutex_exit(&(smp->sm_lock));
 931         return (0);
 932 
 933 fail1:
 934         DTRACE_PROBE1(fail1, int, rc);
 935         mutex_exit(&(smp->sm_lock));
 936 
 937         return (rc);
 938 }
 939 
 940 void
 941 sfxge_mac_stop(sfxge_t *sp)
 942 {
 943         sfxge_mac_t *smp = &(sp->s_mac);
 944         efx_nic_t *enp = sp->s_enp;
 945         efsys_mem_t *esmp = &(smp->sm_mem);
 946 
 947         mutex_enter(&(smp->sm_lock));
 948 
 949         ASSERT3U(smp->sm_state, ==, SFXGE_MAC_STARTED);
 950         ASSERT3P(smp->sm_sp, ==, sp);
 951         smp->sm_state = SFXGE_MAC_INITIALIZED;
 952 
 953         /* If stopping in response to an MC reboot this may fail */
 954         if (!smp->sm_mac_stats_timer_reqd)
 955                 (void) efx_mac_stats_periodic(enp, esmp, 0, B_FALSE);
 956 
 957         sfxge_mac_poll_stop(sp);
 958 
 959         smp->sm_lbolt = 0;
 960 
 961         smp->sm_link_up = B_FALSE;
 962         smp->sm_link_speed = 0;
 963         smp->sm_link_duplex = SFXGE_LINK_DUPLEX_UNKNOWN;
 964 
 965         /* This may call MCDI */
 966         (void) efx_mac_drain(enp, B_TRUE);
 967 
 968         smp->sm_link_mode = EFX_LINK_UNKNOWN;
 969 
 970         efx_port_fini(enp);
 971 
 972         mutex_exit(&(smp->sm_lock));
 973 }
 974 
 975 void
 976 sfxge_mac_fini(sfxge_t *sp)
 977 {
 978         sfxge_mac_t *smp = &(sp->s_mac);
 979         efsys_mem_t *esmp = &(smp->sm_mem);
 980 
 981         ASSERT3U(smp->sm_state, ==, SFXGE_MAC_INITIALIZED);
 982         ASSERT3P(smp->sm_sp, ==, sp);
 983 
 984         /* Tear down the statistics */
 985         sfxge_phy_kstat_fini(sp);
 986         sfxge_mac_kstat_fini(sp);
 987 
 988         smp->sm_state = SFXGE_MAC_UNINITIALIZED;
 989         smp->sm_link_mode = EFX_LINK_UNKNOWN;
 990         smp->sm_promisc = SFXGE_PROMISC_OFF;
 991 
 992         bzero(smp->sm_mcast_addr, SFXGE_MCAST_LIST_MAX * ETHERADDRL);
 993         smp->sm_mcast_count = 0;
 994 
 995         bzero(smp->sm_laa, ETHERADDRL);
 996         smp->sm_laa_valid = B_FALSE;
 997 
 998         bzero(smp->sm_bia, ETHERADDRL);
 999 
1000         smp->sm_fcntl = 0;
1001 
1002         /* Finish with PHY DMA memory */
1003         sfxge_phy_fini(sp);
1004 
1005         /* Teardown the DMA */
1006         sfxge_dma_buffer_destroy(esmp);
1007 
1008         /* Destroy the link poll taskq */
1009         ddi_taskq_destroy(smp->sm_tqp);
1010         smp->sm_tqp = NULL;
1011 
1012         mutex_destroy(&(smp->sm_lock));
1013 
1014         smp->sm_sp = NULL;
1015 
1016         SFXGE_OBJ_CHECK(smp, sfxge_mac_t);
1017 }