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