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 #include <sys/types.h>
  28 #include <sys/ddi.h>
  29 #include <sys/sunddi.h>
  30 #include <sys/gld.h>
  31 
  32 #include <inet/nd.h>
  33 #include <inet/mi.h>
  34 
  35 #include "sfxge.h"
  36 
  37 
  38 typedef enum sfxge_prop_e {
  39         SFXGE_RX_COALESCE_MODE = 0,
  40         SFXGE_RX_SCALE_COUNT,
  41         SFXGE_FCNTL_RESPOND,
  42         SFXGE_FCNTL_GENERATE,
  43         SFXGE_INTR_MODERATION,
  44         SFXGE_ADV_AUTONEG,
  45         SFXGE_ADV_10GFDX,
  46         SFXGE_ADV_1000FDX,
  47         SFXGE_ADV_1000HDX,
  48         SFXGE_ADV_100FDX,
  49         SFXGE_ADV_100HDX,
  50         SFXGE_ADV_10FDX,
  51         SFXGE_ADV_10HDX,
  52         SFXGE_ADV_PAUSE,
  53         SFXGE_ADV_ASM_PAUSE,
  54         SFXGE_LP_AUTONEG,
  55         SFXGE_LP_10GFDX,
  56         SFXGE_LP_1000FDX,
  57         SFXGE_LP_1000HDX,
  58         SFXGE_LP_100FDX,
  59         SFXGE_LP_100HDX,
  60         SFXGE_LP_10FDX,
  61         SFXGE_LP_10HDX,
  62         SFXGE_LP_PAUSE,
  63         SFXGE_LP_ASM_PAUSE,
  64         SFXGE_CAP_AUTONEG,
  65         SFXGE_CAP_10GFDX,
  66         SFXGE_CAP_1000FDX,
  67         SFXGE_CAP_1000HDX,
  68         SFXGE_CAP_100FDX,
  69         SFXGE_CAP_100HDX,
  70         SFXGE_CAP_10FDX,
  71         SFXGE_CAP_10HDX,
  72         SFXGE_CAP_PAUSE,
  73         SFXGE_CAP_ASM_PAUSE,
  74         SFXGE_NPROPS
  75 } sfxge_prop_t;
  76 
  77 
  78 static int
  79 sfxge_gld_nd_get(sfxge_t *sp, unsigned int id, uint32_t *valp)
  80 {
  81         efx_nic_t *enp = sp->s_enp;
  82         unsigned int nprops;
  83         int rc;
  84 
  85         nprops = efx_nic_cfg_get(enp)->enc_phy_nprops;
  86 
  87         if (sp->s_mac.sm_state != SFXGE_MAC_STARTED) {
  88                 rc = ENODEV;
  89                 goto fail1;
  90         }
  91 
  92         ASSERT3U(id, <, nprops + SFXGE_NPROPS);
  93 
  94         if (id < nprops) {
  95                 if ((rc = efx_phy_prop_get(enp, id, 0, valp)) != 0)
  96                         goto fail2;
  97         } else {
  98                 id -= nprops;
  99 
 100                 switch (id) {
 101                 case SFXGE_RX_COALESCE_MODE: {
 102                         sfxge_rx_coalesce_mode_t mode;
 103 
 104                         sfxge_rx_coalesce_mode_get(sp, &mode);
 105 
 106                         *valp = mode;
 107                         break;
 108                 }
 109                 case SFXGE_RX_SCALE_COUNT: {
 110                         unsigned int count;
 111 
 112                         if (sfxge_rx_scale_count_get(sp, &count) != 0)
 113                                 count = 0;
 114 
 115                         *valp = count;
 116                         break;
 117                 }
 118                 case SFXGE_FCNTL_RESPOND: {
 119                         unsigned int fcntl;
 120 
 121                         sfxge_mac_fcntl_get(sp, &fcntl);
 122 
 123                         *valp = (fcntl & EFX_FCNTL_RESPOND) ? 1 : 0;
 124                         break;
 125                 }
 126                 case SFXGE_FCNTL_GENERATE: {
 127                         unsigned int fcntl;
 128 
 129                         sfxge_mac_fcntl_get(sp, &fcntl);
 130 
 131                         *valp = (fcntl & EFX_FCNTL_GENERATE) ? 1 : 0;
 132                         break;
 133                 }
 134                 case SFXGE_INTR_MODERATION: {
 135                         unsigned int us;
 136 
 137                         sfxge_ev_moderation_get(sp, &us);
 138 
 139                         *valp = (long)us;
 140                         break;
 141                 }
 142                 case SFXGE_ADV_AUTONEG: {
 143                         uint32_t mask;
 144 
 145                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 146 
 147                         *valp = (mask & (1 << EFX_PHY_CAP_AN)) ? 1 : 0;
 148                         break;
 149                 }
 150                 case SFXGE_ADV_10GFDX: {
 151                         uint32_t mask;
 152 
 153                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 154 
 155                         *valp = (mask & (1 << EFX_PHY_CAP_10000FDX)) ? 1 : 0;
 156                         break;
 157                 }
 158                 case SFXGE_ADV_1000FDX: {
 159                         uint32_t mask;
 160 
 161                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 162 
 163                         *valp = (mask & (1 << EFX_PHY_CAP_1000FDX)) ? 1 : 0;
 164                         break;
 165                 }
 166                 case SFXGE_ADV_1000HDX: {
 167                         uint32_t mask;
 168 
 169                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 170 
 171                         *valp = (mask & (1 << EFX_PHY_CAP_1000HDX)) ? 1 : 0;
 172                         break;
 173                 }
 174                 case SFXGE_ADV_100FDX: {
 175                         uint32_t mask;
 176 
 177                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 178 
 179                         *valp = (mask & (1 << EFX_PHY_CAP_100FDX)) ? 1 : 0;
 180                         break;
 181                 }
 182                 case SFXGE_ADV_100HDX: {
 183                         uint32_t mask;
 184 
 185                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 186 
 187                         *valp = (mask & (1 << EFX_PHY_CAP_100HDX)) ? 1 : 0;
 188                         break;
 189                 }
 190                 case SFXGE_ADV_10FDX: {
 191                         uint32_t mask;
 192 
 193                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 194 
 195                         *valp = (mask & (1 << EFX_PHY_CAP_10FDX)) ? 1 : 0;
 196                         break;
 197                 }
 198                 case SFXGE_ADV_10HDX: {
 199                         uint32_t mask;
 200 
 201                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 202 
 203                         *valp = (mask & (1 << EFX_PHY_CAP_10HDX)) ? 1 : 0;
 204                         break;
 205                 }
 206                 case SFXGE_ADV_PAUSE: {
 207                         uint32_t mask;
 208 
 209                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 210 
 211                         *valp = (mask & (1 << EFX_PHY_CAP_PAUSE)) ? 1 : 0;
 212                         break;
 213                 }
 214                 case SFXGE_ADV_ASM_PAUSE: {
 215                         uint32_t mask;
 216 
 217                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 218 
 219                         *valp = (mask & (1 << EFX_PHY_CAP_ASYM)) ? 1 : 0;
 220                         break;
 221                 }
 222                 case SFXGE_LP_AUTONEG: {
 223                         uint32_t mask;
 224 
 225                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 226 
 227                         *valp = (mask & (1 << EFX_PHY_CAP_AN)) ? 1 : 0;
 228                         break;
 229                 }
 230                 case SFXGE_LP_10GFDX: {
 231                         uint32_t mask;
 232 
 233                         efx_phy_lp_cap_get(enp, &mask);
 234 
 235                         *valp = (mask & (1 << EFX_PHY_CAP_10000FDX)) ? 1 : 0;
 236                         break;
 237                 }
 238                 case SFXGE_LP_1000FDX: {
 239                         uint32_t mask;
 240 
 241                         efx_phy_lp_cap_get(enp, &mask);
 242 
 243                         *valp = (mask & (1 << EFX_PHY_CAP_1000FDX)) ? 1 : 0;
 244                         break;
 245                 }
 246                 case SFXGE_LP_1000HDX: {
 247                         uint32_t mask;
 248 
 249                         efx_phy_lp_cap_get(enp, &mask);
 250 
 251                         *valp = (mask & (1 << EFX_PHY_CAP_1000HDX)) ? 1 : 0;
 252                         break;
 253                 }
 254                 case SFXGE_LP_100FDX: {
 255                         uint32_t mask;
 256 
 257                         efx_phy_lp_cap_get(enp, &mask);
 258 
 259                         *valp = (mask & (1 << EFX_PHY_CAP_100FDX)) ? 1 : 0;
 260                         break;
 261                 }
 262                 case SFXGE_LP_100HDX: {
 263                         uint32_t mask;
 264 
 265                         efx_phy_lp_cap_get(enp, &mask);
 266 
 267                         *valp = (mask & (1 << EFX_PHY_CAP_100HDX)) ? 1 : 0;
 268                         break;
 269                 }
 270                 case SFXGE_LP_10FDX: {
 271                         uint32_t mask;
 272 
 273                         efx_phy_lp_cap_get(enp, &mask);
 274 
 275                         *valp = (mask & (1 << EFX_PHY_CAP_10FDX)) ? 1 : 0;
 276                         break;
 277                 }
 278                 case SFXGE_LP_10HDX: {
 279                         uint32_t mask;
 280 
 281                         efx_phy_lp_cap_get(enp, &mask);
 282 
 283                         *valp = (mask & (1 << EFX_PHY_CAP_10HDX)) ? 1 : 0;
 284                         break;
 285                 }
 286                 case SFXGE_LP_PAUSE: {
 287                         uint32_t mask;
 288 
 289                         efx_phy_lp_cap_get(enp, &mask);
 290 
 291                         *valp = (mask & (1 << EFX_PHY_CAP_PAUSE)) ? 1 : 0;
 292                         break;
 293                 }
 294                 case SFXGE_LP_ASM_PAUSE: {
 295                         uint32_t mask;
 296 
 297                         efx_phy_lp_cap_get(enp, &mask);
 298 
 299                         *valp = (mask & (1 << EFX_PHY_CAP_ASYM)) ? 1 : 0;
 300                         break;
 301                 }
 302                 case SFXGE_CAP_AUTONEG: {
 303                         uint32_t mask;
 304 
 305                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &mask);
 306 
 307                         *valp = (mask & (1 << EFX_PHY_CAP_AN)) ? 1 : 0;
 308                         break;
 309                 }
 310                 case SFXGE_CAP_10GFDX: {
 311                         uint32_t mask;
 312 
 313                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &mask);
 314 
 315                         *valp = (mask & (1 << EFX_PHY_CAP_10000FDX)) ? 1 : 0;
 316                         break;
 317                 }
 318                 case SFXGE_CAP_1000FDX: {
 319                         uint32_t mask;
 320 
 321                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &mask);
 322 
 323                         *valp = (mask & (1 << EFX_PHY_CAP_1000FDX)) ? 1 : 0;
 324                         break;
 325                 }
 326                 case SFXGE_CAP_1000HDX: {
 327                         uint32_t mask;
 328 
 329                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &mask);
 330 
 331                         *valp = (mask & (1 << EFX_PHY_CAP_1000HDX)) ? 1 : 0;
 332                         break;
 333                 }
 334                 case SFXGE_CAP_100FDX: {
 335                         uint32_t mask;
 336 
 337                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &mask);
 338 
 339                         *valp = (mask & (1 << EFX_PHY_CAP_100FDX)) ? 1 : 0;
 340                         break;
 341                 }
 342                 case SFXGE_CAP_100HDX: {
 343                         uint32_t mask;
 344 
 345                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &mask);
 346 
 347                         *valp = (mask & (1 << EFX_PHY_CAP_100HDX)) ? 1 : 0;
 348                         break;
 349                 }
 350                 case SFXGE_CAP_10FDX: {
 351                         uint32_t mask;
 352 
 353                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &mask);
 354 
 355                         *valp = (mask & (1 << EFX_PHY_CAP_10FDX)) ? 1 : 0;
 356                         break;
 357                 }
 358                 case SFXGE_CAP_10HDX: {
 359                         uint32_t mask;
 360 
 361                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &mask);
 362 
 363                         *valp = (mask & (1 << EFX_PHY_CAP_10HDX)) ? 1 : 0;
 364                         break;
 365                 }
 366                 case SFXGE_CAP_PAUSE: {
 367                         uint32_t mask;
 368 
 369                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &mask);
 370 
 371                         *valp = (mask & (1 << EFX_PHY_CAP_PAUSE)) ? 1 : 0;
 372                         break;
 373                 }
 374                 case SFXGE_CAP_ASM_PAUSE: {
 375                         uint32_t mask;
 376 
 377                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &mask);
 378 
 379                         *valp = (mask & (1 << EFX_PHY_CAP_ASYM)) ? 1 : 0;
 380                         break;
 381                 }
 382                 default:
 383                         ASSERT(B_FALSE);
 384                         break;
 385                 }
 386         }
 387 
 388         return (0);
 389 fail2:
 390         DTRACE_PROBE(fail2);
 391 fail1:
 392         DTRACE_PROBE1(fail1, int, rc);
 393 
 394         return (rc);
 395 }
 396 
 397 #ifdef _USE_NDD_PROPS
 398 static int
 399 sfxge_gld_nd_get_ioctl(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *credp)
 400 {
 401         sfxge_ndd_param_t *snpp = (sfxge_ndd_param_t *)arg;
 402         sfxge_t *sp = snpp->snp_sp;
 403         unsigned int id = snpp->snp_id;
 404         uint32_t val;
 405         int rc;
 406 
 407         _NOTE(ARGUNUSED(q, credp))
 408 
 409         if ((rc = sfxge_gld_nd_get(sp, id, &val)) != 0)
 410                 goto fail1;
 411 
 412         (void) mi_mpprintf(mp, "%d", val);
 413 
 414         return (0);
 415 
 416 fail1:
 417         DTRACE_PROBE1(fail1, int, rc);
 418 
 419         return (rc);
 420 }
 421 #else
 422 static int
 423 sfxge_gld_nd_get_ioctl(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *credp)
 424 {
 425         ASSERT(B_FALSE);
 426         return (-ENODEV);
 427 }
 428 #endif
 429 
 430 
 431 static int
 432 sfxge_gld_nd_set(sfxge_t *sp, unsigned int id, uint32_t val)
 433 {
 434         efx_nic_t *enp = sp->s_enp;
 435         unsigned int nprops;
 436         int rc;
 437 
 438         nprops = efx_nic_cfg_get(enp)->enc_phy_nprops;
 439 
 440         ASSERT3U(id, <, nprops + SFXGE_NPROPS);
 441 
 442         if (id < nprops) {
 443                 if ((rc = efx_phy_prop_set(enp, id, val)) != 0)
 444                         goto fail1;
 445         } else {
 446                 id -= nprops;
 447 
 448                 switch (id) {
 449                 case SFXGE_RX_COALESCE_MODE: {
 450                         sfxge_rx_coalesce_mode_t mode =
 451                             (sfxge_rx_coalesce_mode_t)val;
 452 
 453                         if ((rc = sfxge_rx_coalesce_mode_set(sp, mode)) != 0)
 454                                 goto fail1;
 455 
 456                         break;
 457                 }
 458                 case SFXGE_RX_SCALE_COUNT: {
 459                         unsigned int count = (unsigned int)val;
 460 
 461                         if ((rc = sfxge_rx_scale_count_set(sp, count)) != 0)
 462                                 goto fail1;
 463 
 464                         break;
 465                 }
 466                 case SFXGE_FCNTL_RESPOND: {
 467                         unsigned int fcntl;
 468 
 469                         sfxge_mac_fcntl_get(sp, &fcntl);
 470 
 471                         if (val != 0)
 472                                 fcntl |= EFX_FCNTL_RESPOND;
 473                         else
 474                                 fcntl &= ~EFX_FCNTL_RESPOND;
 475 
 476                         if ((rc = sfxge_mac_fcntl_set(sp, fcntl)) != 0)
 477                                 goto fail1;
 478 
 479                         break;
 480                 }
 481                 case SFXGE_FCNTL_GENERATE: {
 482                         unsigned int fcntl;
 483 
 484                         sfxge_mac_fcntl_get(sp, &fcntl);
 485 
 486                         if (val != 0)
 487                                 fcntl |= EFX_FCNTL_GENERATE;
 488                         else
 489                                 fcntl &= ~EFX_FCNTL_GENERATE;
 490 
 491                         if ((rc = sfxge_mac_fcntl_set(sp, fcntl)) != 0)
 492                                 goto fail1;
 493 
 494                         break;
 495                 }
 496                 case SFXGE_INTR_MODERATION: {
 497                         unsigned int us = (unsigned int)val;
 498 
 499                         if ((rc = sfxge_ev_moderation_set(sp, us)) != 0)
 500                                 goto fail1;
 501                         break;
 502                 }
 503                 case SFXGE_ADV_AUTONEG: {
 504                         uint32_t mask;
 505 
 506                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 507 
 508                         if (val != 0)
 509                                 mask |= (1 << EFX_PHY_CAP_AN);
 510                         else
 511                                 mask &= ~(1 << EFX_PHY_CAP_AN);
 512 
 513                         if ((rc = efx_phy_adv_cap_set(enp, mask)) != 0)
 514                                 goto fail1;
 515 
 516                         break;
 517                 }
 518                 case SFXGE_ADV_10GFDX: {
 519                         uint32_t mask;
 520 
 521                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 522 
 523                         if (val != 0)
 524                                 mask |= (1 << EFX_PHY_CAP_10000FDX);
 525                         else
 526                                 mask &= ~(1 << EFX_PHY_CAP_10000FDX);
 527 
 528                         if ((rc = efx_phy_adv_cap_set(enp, mask)) != 0)
 529                                 goto fail1;
 530 
 531                         break;
 532                 }
 533                 case SFXGE_ADV_1000FDX: {
 534                         uint32_t mask;
 535 
 536                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 537 
 538                         if (val != 0)
 539                                 mask |= (1 << EFX_PHY_CAP_1000FDX);
 540                         else
 541                                 mask &= ~(1 << EFX_PHY_CAP_1000FDX);
 542 
 543                         if ((rc = efx_phy_adv_cap_set(enp, mask)) != 0)
 544                                 goto fail1;
 545 
 546                         break;
 547                 }
 548                 case SFXGE_ADV_1000HDX: {
 549                         uint32_t mask;
 550 
 551                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 552 
 553                         if (val != 0)
 554                                 mask |= (1 << EFX_PHY_CAP_1000HDX);
 555                         else
 556                                 mask &= ~(1 << EFX_PHY_CAP_1000HDX);
 557 
 558                         if ((rc = efx_phy_adv_cap_set(enp, mask)) != 0)
 559                                 goto fail1;
 560 
 561                         break;
 562                 }
 563                 case SFXGE_ADV_100FDX: {
 564                         uint32_t mask;
 565 
 566                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 567 
 568                         if (val != 0)
 569                                 mask |= (1 << EFX_PHY_CAP_100FDX);
 570                         else
 571                                 mask &= ~(1 << EFX_PHY_CAP_100FDX);
 572 
 573                         if ((rc = efx_phy_adv_cap_set(enp, mask)) != 0)
 574                                 goto fail1;
 575 
 576                         break;
 577                 }
 578                 case SFXGE_ADV_100HDX: {
 579                         uint32_t mask;
 580 
 581                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 582 
 583                         if (val != 0)
 584                                 mask |= (1 << EFX_PHY_CAP_100HDX);
 585                         else
 586                                 mask &= ~(1 << EFX_PHY_CAP_100HDX);
 587 
 588                         if ((rc = efx_phy_adv_cap_set(enp, mask)) != 0)
 589                                 goto fail1;
 590 
 591                         break;
 592                 }
 593                 case SFXGE_ADV_10FDX: {
 594                         uint32_t mask;
 595 
 596                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 597 
 598                         if (val != 0)
 599                                 mask |= (1 << EFX_PHY_CAP_10FDX);
 600                         else
 601                                 mask &= ~(1 << EFX_PHY_CAP_10FDX);
 602 
 603                         if ((rc = efx_phy_adv_cap_set(enp, mask)) != 0)
 604                                 goto fail1;
 605 
 606                         break;
 607                 }
 608                 case SFXGE_ADV_10HDX: {
 609                         uint32_t mask;
 610 
 611                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 612 
 613                         if (val != 0)
 614                                 mask |= (1 << EFX_PHY_CAP_10HDX);
 615                         else
 616                                 mask &= ~(1 << EFX_PHY_CAP_10HDX);
 617 
 618                         if ((rc = efx_phy_adv_cap_set(enp, mask)) != 0)
 619                                 goto fail1;
 620 
 621                         break;
 622                 }
 623                 case SFXGE_ADV_PAUSE: {
 624                         uint32_t mask;
 625 
 626                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 627 
 628                         if (val != 0)
 629                                 mask |= (1 << EFX_PHY_CAP_PAUSE);
 630                         else
 631                                 mask &= ~(1 << EFX_PHY_CAP_PAUSE);
 632 
 633                         if ((rc = efx_phy_adv_cap_set(enp, mask)) != 0)
 634                                 goto fail1;
 635 
 636                         break;
 637                 }
 638                 case SFXGE_ADV_ASM_PAUSE: {
 639                         uint32_t mask;
 640 
 641                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &mask);
 642 
 643                         if (val != 0)
 644                                 mask |= (1 << EFX_PHY_CAP_ASYM);
 645                         else
 646                                 mask &= ~(1 << EFX_PHY_CAP_ASYM);
 647 
 648                         if ((rc = efx_phy_adv_cap_set(enp, mask)) != 0)
 649                                 goto fail1;
 650 
 651                         break;
 652                 }
 653                 /* Ignore other kstat writes. Might be for the link partner */
 654                 default:
 655                         DTRACE_PROBE1(ignore_kstat_write, int, id);
 656                 }
 657         }
 658 
 659         return (0);
 660 
 661 fail1:
 662         DTRACE_PROBE1(fail1, int, rc);
 663 
 664         return (rc);
 665 }
 666 
 667 
 668 #ifdef _USE_NDD_PROPS
 669 static int
 670 sfxge_gld_nd_set_ioctl(queue_t *q, mblk_t *mp, char *valp, caddr_t arg,
 671     cred_t *credp)
 672 {
 673         sfxge_ndd_param_t *snpp = (sfxge_ndd_param_t *)arg;
 674         sfxge_t *sp = snpp->snp_sp;
 675         unsigned int id = snpp->snp_id;
 676         long val;
 677         int rc;
 678 
 679         _NOTE(ARGUNUSED(q, mp, credp))
 680 
 681         (void) ddi_strtol(valp, (char **)NULL, 0, &val);
 682 
 683         if ((rc = sfxge_gld_nd_set(sp, id, (uint32_t)val)) != 0)
 684                 goto fail1;
 685 
 686         return (0);
 687 
 688 fail1:
 689         DTRACE_PROBE1(fail1, int, rc);
 690 
 691         return (rc);
 692 }
 693 #else
 694 static int
 695 sfxge_gld_nd_set_ioctl(queue_t *q, mblk_t *mp, char *valp, caddr_t arg,
 696     cred_t *credp)
 697 {
 698         ASSERT(B_FALSE);
 699         return (-ENODEV);
 700 }
 701 #endif
 702 
 703 
 704 static int
 705 sfxge_gld_nd_update(kstat_t *ksp, int rw)
 706 {
 707         sfxge_t *sp = ksp->ks_private;
 708         efx_nic_t *enp = sp->s_enp;
 709         unsigned int nprops;
 710         unsigned int id;
 711         int rc = 0;
 712 
 713         nprops = efx_nic_cfg_get(enp)->enc_phy_nprops;
 714 
 715         for (id = 0; id < nprops + SFXGE_NPROPS; id++) {
 716                 kstat_named_t *knp = &(sp->s_nd_stat[id]);
 717 
 718                 if (rw == KSTAT_READ)
 719                         rc = sfxge_gld_nd_get(sp, id, &(knp->value.ui32));
 720                 else if (rw == KSTAT_WRITE)
 721                         rc = sfxge_gld_nd_set(sp, id, knp->value.ui32);
 722                 else
 723                         rc = EACCES;
 724 
 725                 if (rc != 0)
 726                         goto fail1;
 727         }
 728 
 729         return (0);
 730 
 731 fail1:
 732         DTRACE_PROBE1(fail1, int, rc);
 733         return (rc);
 734 }
 735 
 736 
 737 static sfxge_ndd_param_t        sfxge_ndd_param[] = {
 738         {
 739                 NULL,
 740                 SFXGE_RX_COALESCE_MODE,
 741                 "rx_coalesce_mode",
 742                 sfxge_gld_nd_get_ioctl,
 743                 sfxge_gld_nd_set_ioctl
 744         },
 745         {
 746                 NULL,
 747                 SFXGE_RX_SCALE_COUNT,
 748                 "rx_scale_count",
 749                 sfxge_gld_nd_get_ioctl,
 750                 sfxge_gld_nd_set_ioctl
 751         },
 752         {
 753                 NULL,
 754                 SFXGE_FCNTL_RESPOND,
 755                 "fcntl_respond",
 756                 sfxge_gld_nd_get_ioctl,
 757                 sfxge_gld_nd_set_ioctl
 758         },
 759         {
 760                 NULL,
 761                 SFXGE_FCNTL_GENERATE,
 762                 "fcntl_generate",
 763                 sfxge_gld_nd_get_ioctl,
 764                 sfxge_gld_nd_set_ioctl
 765         },
 766         {
 767                 NULL,
 768                 SFXGE_INTR_MODERATION,
 769                 "intr_moderation",
 770                 sfxge_gld_nd_get_ioctl,
 771                 sfxge_gld_nd_set_ioctl
 772         },
 773         {
 774                 NULL,
 775                 SFXGE_ADV_AUTONEG,
 776                 "adv_cap_autoneg",
 777                 sfxge_gld_nd_get_ioctl,
 778                 sfxge_gld_nd_set_ioctl
 779         },
 780         {
 781                 NULL,
 782                 SFXGE_ADV_10GFDX,
 783                 "adv_cap_10gfdx",
 784                 sfxge_gld_nd_get_ioctl,
 785                 sfxge_gld_nd_set_ioctl
 786         },
 787         {
 788                 NULL,
 789                 SFXGE_ADV_1000FDX,
 790                 "adv_cap_1000fdx",
 791                 sfxge_gld_nd_get_ioctl,
 792                 sfxge_gld_nd_set_ioctl
 793         },
 794         {
 795                 NULL,
 796                 SFXGE_ADV_1000HDX,
 797                 "adv_cap_1000hdx",
 798                 sfxge_gld_nd_get_ioctl,
 799                 sfxge_gld_nd_set_ioctl
 800         },
 801         {
 802                 NULL,
 803                 SFXGE_ADV_100FDX,
 804                 "adv_cap_100fdx",
 805                 sfxge_gld_nd_get_ioctl,
 806                 sfxge_gld_nd_set_ioctl
 807         },
 808         {
 809                 NULL,
 810                 SFXGE_ADV_100HDX,
 811                 "adv_cap_100hdx",
 812                 sfxge_gld_nd_get_ioctl,
 813                 sfxge_gld_nd_set_ioctl
 814         },
 815         {
 816                 NULL,
 817                 SFXGE_ADV_10FDX,
 818                 "adv_cap_10fdx",
 819                 sfxge_gld_nd_get_ioctl,
 820                 sfxge_gld_nd_set_ioctl
 821         },
 822         {
 823                 NULL,
 824                 SFXGE_ADV_10HDX,
 825                 "adv_cap_10hdx",
 826                 sfxge_gld_nd_get_ioctl,
 827                 sfxge_gld_nd_set_ioctl
 828         },
 829         {
 830                 NULL,
 831                 SFXGE_ADV_PAUSE,
 832                 "adv_cap_pause",
 833                 sfxge_gld_nd_get_ioctl,
 834                 sfxge_gld_nd_set_ioctl
 835         },
 836         {
 837                 NULL,
 838                 SFXGE_ADV_ASM_PAUSE,
 839                 "adv_cap_asm_pause",
 840                 sfxge_gld_nd_get_ioctl,
 841                 sfxge_gld_nd_set_ioctl
 842         },
 843         {
 844                 NULL,
 845                 SFXGE_LP_AUTONEG,
 846                 "lp_cap_autoneg",
 847                 sfxge_gld_nd_get_ioctl,
 848                 NULL
 849         },
 850         {
 851                 NULL,
 852                 SFXGE_LP_10GFDX,
 853                 "lp_cap_10gfdx",
 854                 sfxge_gld_nd_get_ioctl,
 855                 NULL
 856         },
 857         {
 858                 NULL,
 859                 SFXGE_LP_1000FDX,
 860                 "lp_cap_1000fdx",
 861                 sfxge_gld_nd_get_ioctl,
 862                 NULL
 863         },
 864         {
 865                 NULL,
 866                 SFXGE_LP_1000HDX,
 867                 "lp_cap_1000hdx",
 868                 sfxge_gld_nd_get_ioctl,
 869                 NULL
 870         },
 871         {
 872                 NULL,
 873                 SFXGE_LP_100FDX,
 874                 "lp_cap_100fdx",
 875                 sfxge_gld_nd_get_ioctl,
 876                 NULL
 877         },
 878         {
 879                 NULL,
 880                 SFXGE_LP_100HDX,
 881                 "lp_cap_100hdx",
 882                 sfxge_gld_nd_get_ioctl,
 883                 NULL
 884         },
 885         {
 886                 NULL,
 887                 SFXGE_LP_10FDX,
 888                 "lp_cap_10fdx",
 889                 sfxge_gld_nd_get_ioctl,
 890                 NULL
 891         },
 892         {
 893                 NULL,
 894                 SFXGE_LP_10HDX,
 895                 "lp_cap_10hdx",
 896                 sfxge_gld_nd_get_ioctl,
 897                 NULL
 898         },
 899         {
 900                 NULL,
 901                 SFXGE_LP_PAUSE,
 902                 "lp_cap_pause",
 903                 sfxge_gld_nd_get_ioctl,
 904                 NULL
 905         },
 906         {
 907                 NULL,
 908                 SFXGE_LP_ASM_PAUSE,
 909                 "lp_cap_asm_pause",
 910                 sfxge_gld_nd_get_ioctl,
 911                 NULL
 912         },
 913         {
 914                 NULL,
 915                 SFXGE_CAP_AUTONEG,
 916                 "cap_autoneg",
 917                 sfxge_gld_nd_get_ioctl,
 918                 NULL
 919         },
 920         {
 921                 NULL,
 922                 SFXGE_CAP_10GFDX,
 923                 "cap_10gfdx",
 924                 sfxge_gld_nd_get_ioctl,
 925                 NULL
 926         },
 927         {
 928                 NULL,
 929                 SFXGE_CAP_1000FDX,
 930                 "cap_1000fdx",
 931                 sfxge_gld_nd_get_ioctl,
 932                 NULL
 933         },
 934         {
 935                 NULL,
 936                 SFXGE_CAP_1000HDX,
 937                 "cap_1000hdx",
 938                 sfxge_gld_nd_get_ioctl,
 939                 NULL
 940         },
 941         {
 942                 NULL,
 943                 SFXGE_CAP_100FDX,
 944                 "cap_100fdx",
 945                 sfxge_gld_nd_get_ioctl,
 946                 NULL
 947         },
 948         {
 949                 NULL,
 950                 SFXGE_CAP_100HDX,
 951                 "cap_100hdx",
 952                 sfxge_gld_nd_get_ioctl,
 953                 NULL
 954         },
 955         {
 956                 NULL,
 957                 SFXGE_CAP_10FDX,
 958                 "cap_10fdx",
 959                 sfxge_gld_nd_get_ioctl,
 960                 NULL
 961         },
 962         {
 963                 NULL,
 964                 SFXGE_CAP_10HDX,
 965                 "cap_10hdx",
 966                 sfxge_gld_nd_get_ioctl,
 967                 NULL
 968         },
 969         {
 970                 NULL,
 971                 SFXGE_CAP_PAUSE,
 972                 "cap_pause",
 973                 sfxge_gld_nd_get_ioctl,
 974                 NULL
 975         },
 976         {
 977                 NULL,
 978                 SFXGE_CAP_ASM_PAUSE,
 979                 "cap_asm_pause",
 980                 sfxge_gld_nd_get_ioctl,
 981                 NULL
 982         }
 983 };
 984 
 985 
 986 int
 987 sfxge_gld_nd_register(sfxge_t *sp)
 988 {
 989 #ifdef _USE_NDD_PROPS
 990         caddr_t *ndhp = &(sp->s_ndh);
 991 #endif
 992         efx_nic_t *enp = sp->s_enp;
 993         unsigned int nprops;
 994         unsigned int id;
 995         char name[MAXNAMELEN];
 996         kstat_t *ksp;
 997         int rc;
 998 
 999         ASSERT3P(sp->s_ndh, ==, NULL);
1000 
1001         nprops = efx_nic_cfg_get(enp)->enc_phy_nprops;
1002 
1003 #ifdef _USE_NDD_PROPS
1004         /* Register with the NDD framework */
1005         if ((sp->s_ndp = kmem_zalloc(sizeof (sfxge_ndd_param_t) *
1006             (nprops + SFXGE_NPROPS), KM_NOSLEEP)) == NULL) {
1007                 rc = ENOMEM;
1008                 goto fail1;
1009         }
1010 
1011         for (id = 0; id < nprops; id++) {
1012                 sfxge_ndd_param_t *snpp = &(sp->s_ndp[id]);
1013 
1014                 snpp->snp_sp = sp;
1015                 snpp->snp_id = id;
1016                 snpp->snp_name = efx_phy_prop_name(enp, id);
1017                 snpp->snp_get = sfxge_gld_nd_get_ioctl;
1018                 snpp->snp_set = sfxge_gld_nd_set_ioctl;
1019 
1020                 ASSERT(snpp->snp_name != NULL);
1021 
1022                 (void) nd_load(ndhp, (char *)(snpp->snp_name),
1023                     snpp->snp_get, snpp->snp_set, (caddr_t)snpp);
1024         }
1025 
1026         for (id = 0; id < SFXGE_NPROPS; id++) {
1027                 sfxge_ndd_param_t *snpp = &(sp->s_ndp[id + nprops]);
1028 
1029                 *snpp = sfxge_ndd_param[id];
1030                 ASSERT3U(snpp->snp_id, ==, id);
1031 
1032                 snpp->snp_sp = sp;
1033                 snpp->snp_id += nprops;
1034 
1035                 (void) nd_load(ndhp, (char *)(snpp->snp_name),
1036                     snpp->snp_get, snpp->snp_set, (caddr_t)snpp);
1037         }
1038 #endif
1039 
1040         /* Also create a kstat set */
1041         (void) snprintf(name, MAXNAMELEN - 1, "%s_ndd",
1042             ddi_driver_name(sp->s_dip));
1043 
1044         if ((ksp = kstat_create((char *)ddi_driver_name(sp->s_dip),
1045             ddi_get_instance(sp->s_dip), name, "ndd", KSTAT_TYPE_NAMED,
1046             (nprops + SFXGE_NPROPS), KSTAT_FLAG_WRITABLE)) == NULL) {
1047                 rc = ENOMEM;
1048                 goto fail2;
1049         }
1050 
1051         sp->s_nd_ksp = ksp;
1052 
1053         ksp->ks_update = sfxge_gld_nd_update;
1054         ksp->ks_private = sp;
1055 
1056         sp->s_nd_stat = ksp->ks_data;
1057 
1058         for (id = 0; id < nprops; id++) {
1059                 kstat_named_t *knp = &(sp->s_nd_stat[id]);
1060 
1061                 kstat_named_init(knp, (char *)efx_phy_prop_name(enp, id),
1062                     KSTAT_DATA_UINT32);
1063         }
1064 
1065         for (id = 0; id < SFXGE_NPROPS; id++) {
1066                 kstat_named_t *knp = &(sp->s_nd_stat[id + nprops]);
1067                 sfxge_ndd_param_t *snpp = &sfxge_ndd_param[id];
1068 
1069                 kstat_named_init(knp, (char *)(snpp->snp_name),
1070                     KSTAT_DATA_UINT32);
1071         }
1072 
1073         kstat_install(ksp);
1074 
1075         return (0);
1076 
1077 fail2:
1078         DTRACE_PROBE(fail2);
1079 
1080 #ifdef _USE_NDD_PROPS
1081         nd_free(ndhp);
1082         sp->s_ndh = NULL;
1083 
1084         kmem_free(sp->s_ndp, sizeof (sfxge_ndd_param_t) *
1085             (nprops + SFXGE_NPROPS));
1086         sp->s_ndp = NULL;
1087 
1088 fail1:
1089         DTRACE_PROBE1(fail1, int, rc);
1090 #endif
1091 
1092         return (rc);
1093 }
1094 
1095 
1096 void
1097 sfxge_gld_nd_unregister(sfxge_t *sp)
1098 {
1099 #ifdef _USE_NDD_PROPS
1100         caddr_t *ndhp = &(sp->s_ndh);
1101 #endif
1102         efx_nic_t *enp = sp->s_enp;
1103         unsigned int nprops;
1104 
1105         nprops = efx_nic_cfg_get(enp)->enc_phy_nprops;
1106 
1107         /* Destroy the kstat set */
1108         kstat_delete(sp->s_nd_ksp);
1109         sp->s_nd_ksp = NULL;
1110         sp->s_nd_stat = NULL;
1111 
1112         /* Unregister from the NDD framework */
1113 #ifdef _USE_NDD_PROPS
1114         nd_free(ndhp);
1115 
1116         sp->s_ndh = NULL;
1117 
1118         kmem_free(sp->s_ndp, sizeof (sfxge_ndd_param_t) *
1119             (nprops + SFXGE_NPROPS));
1120         sp->s_ndp = NULL;
1121 #endif
1122 }