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 (c) 2009-2012 Emulex. All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 
  29 /*
  30  * Source file containing the implementation of the driver entry points
  31  * and related helper functions
  32  */
  33 
  34 #include <oce_impl.h>
  35 #include <oce_stat.h>
  36 #include <oce_ioctl.h>
  37 
  38 /* ---[ globals and externs ]-------------------------------------------- */
  39 const char oce_ident_string[] = OCE_IDENT_STRING;
  40 const char oce_mod_name[] = OCE_MOD_NAME;
  41 
  42 /* driver properties */
  43 static const char tx_reclaim[]           = "tx_reclaim";
  44 static const char flow_control[]         = "flow_control";
  45 static const char mtu_prop_name[]        = "oce_default_mtu";
  46 static const char tx_ring_size_name[]    = "tx_ring_size";
  47 static const char tx_bcopy_limit_name[]  = "tx_bcopy_limit";
  48 static const char rx_bcopy_limit_name[]  = "rx_bcopy_limit";
  49 static const char rx_frag_size_name[]    = "rx_frag_size";
  50 static const char rx_max_bufs_name[]     = "rx_max_bufs";
  51 static const char fm_cap_name[]          = "oce_fm_capability";
  52 static const char log_level_name[]       = "oce_log_level";
  53 static const char lso_capable_name[]     = "lso_capable";
  54 static const char rx_pkt_per_intr_name[] = "rx_pkts_per_intr";
  55 static const char tx_reclaim_threshold_name[] = "tx_reclaim_threshold";
  56 static const char rx_rings_name[] = "max_rx_rings";
  57 static const char rx_group_name[] = "max_rx_rings_per_group";
  58 static const char tx_rings_name[] = "max_tx_rings";
  59 
  60 /* --[ static function prototypes here ]------------------------------- */
  61 static int oce_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd);
  62 static int oce_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
  63 static int oce_quiesce(dev_info_t *dip);
  64 static int oce_suspend(dev_info_t *dip);
  65 static int oce_resume(dev_info_t *dip);
  66 static void oce_unconfigure(struct oce_dev *dev);
  67 static void oce_init_locks(struct oce_dev *dev);
  68 static void oce_destroy_locks(struct oce_dev *dev);
  69 static void oce_get_params(struct oce_dev *dev);
  70 static int oce_get_prop(struct oce_dev *dev, char *propname, int minval,
  71     int maxval, int defval, uint32_t *values);
  72 static void oce_reset_wd_timer(struct oce_dev *dev);
  73 static void oce_wd_timer(void *arg);
  74 static void oce_set_wd_timer(struct oce_dev *dev);
  75 int oce_alloc_queues(struct oce_dev *dev);
  76 void oce_free_queues(struct oce_dev *dev);
  77 
  78 static struct cb_ops oce_cb_ops = {
  79         nulldev,                /* cb_open */
  80         nulldev,                /* cb_close */
  81         nodev,                  /* cb_strategy */
  82         nodev,                  /* cb_print */
  83         nodev,                  /* cb_dump */
  84         nodev,                  /* cb_read */
  85         nodev,                  /* cb_write */
  86         nodev,                  /* cb_ioctl */
  87         nodev,                  /* cb_devmap */
  88         nodev,                  /* cb_mmap */
  89         nodev,                  /* cb_segmap */
  90         nochpoll,               /* cb_chpoll */
  91         ddi_prop_op,    /* cb_prop_op */
  92         NULL,                   /* cb_stream */
  93         D_MP,                   /* cb_flag */
  94         CB_REV,                 /* cb_rev */
  95         nodev,                  /* cb_aread */
  96         nodev                   /* cb_awrite */
  97 };
  98 
  99 static struct dev_ops oce_dev_ops = {
 100         DEVO_REV,       /* devo_rev */
 101         0,              /* devo_refcnt */
 102         NULL,           /* devo_getinfo */
 103         NULL,           /* devo_identify */
 104         nulldev,        /* devo_probe */
 105         oce_attach,     /* devo_attach */
 106         oce_detach,     /* devo_detach */
 107         nodev,          /* devo_reset */
 108         &oce_cb_ops,        /* devo_cb_ops */
 109         NULL,           /* devo_bus_ops */
 110         nodev,          /* devo_power */
 111         oce_quiesce     /* devo_quiesce */
 112 };
 113 
 114 static struct modldrv oce_drv = {
 115         &mod_driverops,     /* Type of module.  This one is a driver */
 116         (char *)oce_ident_string, /* Description string */
 117         &oce_dev_ops,       /* driver ops */
 118 };
 119 
 120 static struct modlinkage oce_mod_linkage = {
 121         MODREV_1, &oce_drv, NULL
 122 };
 123 
 124 #define OCE_M_CB_FLAGS  (MC_IOCTL | MC_GETCAPAB | MC_PROPERTIES)
 125 static mac_callbacks_t oce_mac_cb = {
 126         OCE_M_CB_FLAGS,         /* mc_callbacks */
 127         oce_m_stat,             /* mc_getstat */
 128         oce_m_start,            /* mc_start */
 129         oce_m_stop,             /* mc_stop */
 130         oce_m_promiscuous,      /* mc_setpromisc */
 131         oce_m_multicast,        /* mc_multicast */
 132         NULL,                   /* mc_unicast */
 133         NULL,                   /* mc_tx */
 134         NULL,                   /* mc_reserve */
 135         oce_m_ioctl,            /* mc_ioctl */
 136         oce_m_getcap,           /* mc_getcapab */
 137         NULL,                   /* open */
 138         NULL,                   /* close */
 139         oce_m_setprop,          /* set properties */
 140         oce_m_getprop,          /* get properties */
 141         oce_m_propinfo          /* properties info */
 142 };
 143 
 144 
 145 /* array of properties supported by this driver */
 146 char *oce_priv_props[] = {
 147         "_tx_rings",
 148         "_tx_ring_size",
 149         "_tx_bcopy_limit",
 150         "_tx_reclaim_threshold",
 151         "_rx_rings",
 152         "_rx_rings_per_group",
 153         "_rx_ring_size",
 154         "_rx_bcopy_limit",
 155         "_rx_pkts_per_intr",
 156         "_log_level",
 157         NULL
 158 };
 159 
 160 int oce_irm_enable = -1;
 161 
 162 extern int oce_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg,
 163     void *arg1, void *arg2);
 164 
 165 /* Module Init */
 166 int
 167 _info(struct modinfo *modinfop)
 168 {
 169         return (mod_info(&oce_mod_linkage, modinfop));
 170 } /* _info */
 171 
 172 int
 173 _init(void)
 174 {
 175         int ret = 0;
 176 
 177         /* install the module */
 178         mac_init_ops(&oce_dev_ops, OCE_MOD_NAME);
 179 
 180         ret = mod_install(&oce_mod_linkage);
 181         if (ret) {
 182                 cmn_err(CE_WARN, "mod_install failed  rval=%x", ret);
 183         }
 184 
 185         return (ret);
 186 } /* _init */
 187 
 188 
 189 int
 190 _fini(void)
 191 {
 192         int ret = 0;
 193 
 194         /* remove the module */
 195         ret = mod_remove(&oce_mod_linkage);
 196         if (ret != 0) {
 197                 return (ret);
 198         }
 199 
 200         mac_fini_ops(&oce_dev_ops);
 201 
 202         return (ret);
 203 } /* _fini */
 204 
 205 
 206 static int
 207 oce_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 208 {
 209         int ret = 0;
 210         struct oce_dev *dev = NULL;
 211         mac_register_t *mac;
 212 
 213         switch (cmd) {
 214         case DDI_RESUME:
 215                 return (oce_resume(dip));
 216         default:
 217                 return (DDI_FAILURE);
 218 
 219         case DDI_ATTACH:
 220                 break;
 221         }
 222 
 223         /* allocate dev */
 224         dev = kmem_zalloc(sizeof (struct oce_dev), KM_SLEEP);
 225 
 226         /* populate the dev structure */
 227         dev->dip = dip;
 228         dev->dev_id = ddi_get_instance(dip);
 229         dev->suspended = B_FALSE;
 230 
 231         /* get the parameters */
 232         oce_get_params(dev);
 233 
 234         /*
 235          * set the ddi driver private data pointer. This is
 236          * sent to all mac callback entry points
 237          */
 238         ddi_set_driver_private(dip, dev);
 239 
 240         dev->attach_state |= ATTACH_DEV_INIT;
 241 
 242         oce_fm_init(dev);
 243         dev->attach_state |= ATTACH_FM_INIT;
 244 
 245         ret = pci_config_setup(dev->dip, &dev->pci_cfg_handle);
 246         if (ret != DDI_SUCCESS) {
 247                 oce_log(dev, CE_WARN, MOD_CONFIG,
 248                     "Map PCI config failed with  %d", ret);
 249                 goto attach_fail;
 250         }
 251         dev->attach_state |= ATTACH_PCI_CFG;
 252 
 253         ret = oce_identify_hw(dev);
 254 
 255         if (ret != DDI_SUCCESS) {
 256                 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 257                     "Device Unknown");
 258                 goto attach_fail;
 259         }
 260 
 261         /* setup PCI bars */
 262         ret = oce_pci_init(dev);
 263         if (ret != DDI_SUCCESS) {
 264                 oce_log(dev, CE_WARN, MOD_CONFIG,
 265                     "PCI initialization failed with %d", ret);
 266                 goto attach_fail;
 267         }
 268         dev->attach_state |= ATTACH_PCI_INIT;
 269 
 270         /* initialize locks */
 271         oce_init_locks(dev);
 272         dev->attach_state |= ATTACH_LOCK_INIT;
 273 
 274         /* HW init */
 275         ret = oce_hw_init(dev);
 276         if (ret != DDI_SUCCESS) {
 277                 oce_log(dev, CE_WARN, MOD_CONFIG,
 278                     "HW initialization failed with %d", ret);
 279                 goto attach_fail;
 280         }
 281         dev->attach_state |= ATTACH_HW_INIT;
 282 
 283         /* Register IRM callback handler */
 284         if (oce_irm_enable != 0) {
 285                 ret = ddi_cb_register(dev->dip, DDI_CB_FLAG_INTR, oce_cbfunc,
 286                     dev, NULL, &dev->cb_handle);
 287                 if (ret != 0) {
 288                         oce_log(dev, CE_NOTE, MOD_CONFIG,
 289                             "Unable to register IRM callback: 0x%x", ret);
 290                         oce_irm_enable = 0;
 291                 } else {
 292                         dev->attach_state |= ATTACH_CB_REG;
 293                         oce_irm_enable = 1;
 294                 }
 295         }
 296 
 297         /* Adjusting number of groups and rings */
 298         oce_group_rings(dev);
 299 
 300         ret = oce_setup_intr(dev);
 301         if (ret != DDI_SUCCESS) {
 302                 oce_log(dev, CE_WARN, MOD_CONFIG,
 303                     "Interrupt setup failed with %d", ret);
 304                 goto attach_fail;
 305         }
 306         dev->attach_state |= ATTACH_SETUP_INTR;
 307 
 308         if (oce_alloc_queues(dev) != DDI_SUCCESS) {
 309                 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 310                     "Failed to allocate rings");
 311                 goto attach_fail;
 312         }
 313         dev->attach_state |= ATTACH_ALLOC_QUEUES;
 314 
 315         ret = oce_stat_init(dev);
 316         if (ret != DDI_SUCCESS) {
 317                 oce_log(dev, CE_WARN, MOD_CONFIG,
 318                     "kstat setup Failed with %d", ret);
 319                 goto attach_fail;
 320         }
 321         dev->attach_state |= ATTACH_STAT_INIT;
 322 
 323         if (oce_setup_handlers(dev) != DDI_SUCCESS) {
 324                 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 325                     "Failed to Setup handlers");
 326                 goto attach_fail;
 327         }
 328         dev->attach_state |= ATTACH_REG_INTR_HANDLE;
 329 
 330         /* mac_register_t */
 331         oce_log(dev, CE_NOTE, MOD_CONFIG,
 332             "MAC_VERSION = 0x%x", MAC_VERSION);
 333         mac = mac_alloc(MAC_VERSION);
 334         if (mac == NULL) {
 335                 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 336                     "MAC allocation Failed");
 337                 goto attach_fail;
 338         }
 339         /*
 340          * fill the mac structure before calling mac_register
 341          */
 342         mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
 343         mac->m_driver = dev;
 344         mac->m_dip = dip;
 345         mac->m_src_addr = dev->mac_addr;
 346         mac->m_callbacks = &oce_mac_cb;
 347         mac->m_min_sdu = 0;
 348         mac->m_max_sdu = dev->mtu;
 349         mac->m_margin = VTAG_SIZE;
 350         mac->m_priv_props = oce_priv_props;
 351         mac->m_v12n = MAC_VIRT_LEVEL1;
 352 
 353         oce_log(dev, CE_NOTE, MOD_CONFIG,
 354             "Driver Private structure = 0x%p", (void *)dev);
 355 
 356         /* now register with GLDv3 */
 357         ret = mac_register(mac, (mac_handle_t *)&dev->mac_handle);
 358         /* regardless of the status, free mac_register */
 359         mac_free(mac);
 360         mac = NULL;
 361         if (ret != DDI_SUCCESS) {
 362                 oce_log(dev, CE_WARN, MOD_CONFIG,
 363                     "MAC registration failed :0x%x", ret);
 364                 goto attach_fail;
 365         }
 366 
 367         /* correct link status only after start */
 368         dev->link_status = LINK_STATE_UNKNOWN;
 369         mac_link_update(dev->mac_handle, dev->link_status);
 370 
 371         dev->attach_state |= ATTACH_MAC_REG;
 372 
 373         oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
 374             "ATTACH SUCCESS");
 375 
 376         return (DDI_SUCCESS);
 377 
 378 attach_fail:
 379         oce_unconfigure(dev);
 380         return (DDI_FAILURE);
 381 } /* oce_attach */
 382 
 383 static int
 384 oce_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 385 {
 386         struct oce_dev *dev;
 387         int ret = DDI_SUCCESS;
 388 
 389         dev = ddi_get_driver_private(dip);
 390         if (dev == NULL) {
 391                 return (DDI_FAILURE);
 392         }
 393 
 394         switch (cmd) {
 395         default:
 396                 return (DDI_FAILURE);
 397         case DDI_SUSPEND:
 398                 return (oce_suspend(dip));
 399         case DDI_DETACH:
 400                 break;
 401         } /* switch cmd */
 402 
 403         /* check if the detach is called with out stopping */
 404         DEV_LOCK(dev);
 405         if (dev->state & STATE_MAC_STARTED) {
 406                 dev->state &= ~STATE_MAC_STARTED;
 407                 oce_stop(dev);
 408                 DEV_UNLOCK(dev);
 409         } else
 410                 DEV_UNLOCK(dev);
 411 
 412         oce_unconfigure(dev);
 413         return (ret);
 414 } /* oce_detach */
 415 
 416 static int
 417 oce_quiesce(dev_info_t *dip)
 418 {
 419         int ret = DDI_SUCCESS;
 420         struct oce_dev *dev = ddi_get_driver_private(dip);
 421 
 422         if (dev == NULL) {
 423                 return (DDI_FAILURE);
 424         }
 425         if (dev->suspended) {
 426                 return (DDI_SUCCESS);
 427         }
 428 
 429         if (!LANCER_CHIP(dev)) {
 430                 oce_chip_di(dev);
 431 
 432                 ret = oce_reset_fun(dev);
 433         } else {
 434                 LANCER_IP_RESET;
 435         }
 436 
 437         return (ret);
 438 }
 439 
 440 static int
 441 oce_suspend(dev_info_t *dip)
 442 {
 443         struct oce_dev *dev = ddi_get_driver_private(dip);
 444         int i;
 445 
 446         mutex_enter(&dev->dev_lock);
 447         /* Suspend the card */
 448         if (dev->suspended || (!(dev->state & STATE_MAC_STARTED))) {
 449                 mutex_exit(&dev->dev_lock);
 450                 return (DDI_SUCCESS);
 451         }
 452         dev->suspended = B_TRUE;
 453 
 454         /* stop the groups */
 455         for (i = 0; i < dev->num_rx_groups; i++) {
 456                 mutex_enter(&dev->rx_group[i].grp_lock);
 457                 oce_suspend_group_rings(&dev->rx_group[i]);
 458                 oce_stop_group(&dev->rx_group[i], B_FALSE);
 459                 mutex_exit(&dev->rx_group[i].grp_lock);
 460         }
 461 
 462         /* stop the adapter */
 463         oce_stop(dev);
 464 
 465         mutex_exit(&dev->dev_lock);
 466         oce_disable_wd_timer(dev);
 467         return (DDI_SUCCESS);
 468 } /* oce_suspend */
 469 
 470 static int
 471 oce_resume(dev_info_t *dip)
 472 {
 473         struct oce_dev *dev;
 474         int i, ret = DDI_SUCCESS;
 475 
 476         /* get the dev pointer from dip */
 477         dev = ddi_get_driver_private(dip);
 478         if (dev == NULL) {
 479                 return (DDI_FAILURE);
 480         }
 481         mutex_enter(&dev->dev_lock);
 482         if (!dev->suspended) {
 483                 mutex_exit(&dev->dev_lock);
 484                 return (DDI_SUCCESS);
 485         }
 486         if (dev->state & STATE_MAC_STARTED) {
 487                 if ((ret = oce_start(dev)) != DDI_SUCCESS) {
 488                         goto resume_finish;
 489                 }
 490 
 491                 /* re-start the groups */
 492                 for (i = 0; i < dev->num_rx_groups; i++) {
 493                         mutex_enter(&dev->rx_group[i].grp_lock);
 494                         ret = oce_start_group(&dev->rx_group[i], B_FALSE);
 495                         if (ret == DDI_SUCCESS) {
 496                                 ret = oce_resume_group_rings(&dev->rx_group[i]);
 497                         }
 498                         mutex_exit(&dev->rx_group[i].grp_lock);
 499                         if (ret != DDI_SUCCESS)
 500                                 goto resume_finish;
 501                 }
 502                 oce_enable_wd_timer(dev);
 503         }
 504         dev->suspended = B_FALSE;
 505 
 506 resume_finish:
 507         mutex_exit(&dev->dev_lock);
 508         return (ret);
 509 } /* oce_resume */
 510 
 511 static void
 512 oce_init_locks(struct oce_dev *dev)
 513 {
 514         /* initialize locks */
 515         mutex_init(&dev->dev_lock, NULL, MUTEX_DRIVER,
 516             DDI_INTR_PRI(dev->intr_pri));
 517         mutex_init(&dev->bmbx_lock, NULL, MUTEX_DRIVER,
 518             DDI_INTR_PRI(dev->intr_pri));
 519         mutex_init(&dev->wd_lock, NULL, MUTEX_DRIVER,
 520             DDI_INTR_PRI(dev->intr_pri));
 521         mutex_init(&dev->stat_lock, NULL, MUTEX_DRIVER,
 522             DDI_INTR_PRI(dev->intr_pri));
 523 } /* oce_init_locks */
 524 
 525 static void
 526 oce_destroy_locks(struct oce_dev *dev)
 527 {
 528         mutex_destroy(&dev->dev_lock);
 529         mutex_destroy(&dev->bmbx_lock);
 530         mutex_destroy(&dev->wd_lock);
 531         mutex_destroy(&dev->stat_lock);
 532 } /* oce_destroy_locks */
 533 
 534 static void
 535 oce_unconfigure(struct oce_dev *dev)
 536 {
 537         uint32_t state = dev->attach_state;
 538 
 539         if (state & ATTACH_MAC_REG) {
 540                 (void) mac_unregister(dev->mac_handle);
 541         }
 542         if (state & ATTACH_REG_INTR_HANDLE) {
 543                 oce_remove_handler(dev);
 544         }
 545         if (state & ATTACH_STAT_INIT) {
 546                 oce_stat_fini(dev);
 547         }
 548         if (state & ATTACH_CB_REG) {
 549                 (void) ddi_cb_unregister(dev->cb_handle);
 550         }
 551         if (state & ATTACH_SETUP_INTR) {
 552                 (void) oce_teardown_intr(dev);
 553         }
 554         if (state & ATTACH_ALLOC_QUEUES) {
 555                 oce_free_queues(dev);
 556         }
 557         if (state & ATTACH_HW_INIT) {
 558                 oce_hw_fini(dev);
 559         }
 560         if (state & ATTACH_LOCK_INIT) {
 561                 oce_destroy_locks(dev);
 562         }
 563         if (state & ATTACH_PCI_INIT) {
 564                 oce_pci_fini(dev);
 565         }
 566         if (state & ATTACH_PCI_CFG) {
 567                 pci_config_teardown(&dev->pci_cfg_handle);
 568         }
 569         if (state & ATTACH_FM_INIT) {
 570                 oce_fm_fini(dev);
 571         }
 572         if (state & ATTACH_DEV_INIT) {
 573                 ddi_set_driver_private(dev->dip, NULL);
 574                 kmem_free(dev, sizeof (struct oce_dev));
 575         }
 576 } /* oce_unconfigure */
 577 
 578 static void
 579 oce_get_params(struct oce_dev *dev)
 580 {
 581         uint32_t log_level;
 582         uint16_t mod_mask;
 583         uint16_t severity;
 584         /*
 585          * Allowed values for the driver parameters. If all values in a range
 586          * is allowed, the the array has only one value.
 587          */
 588         uint32_t fc_values[] = {OCE_FC_NONE, OCE_FC_TX, OCE_FC_RX,
 589             OCE_DEFAULT_FLOW_CONTROL, END};
 590         uint32_t mtu_values[] = {OCE_MIN_MTU, OCE_MAX_MTU, END};
 591         uint32_t tx_rs_values[] = {SIZE_256, SIZE_512, SIZE_1K, SIZE_2K, END};
 592         uint32_t tx_bcl_values[] = {SIZE_128, SIZE_256, SIZE_512, SIZE_1K,
 593             SIZE_2K, END};
 594         uint32_t rx_bcl_values[] = {SIZE_128, SIZE_256, SIZE_512, SIZE_1K,
 595             SIZE_2K, END};
 596         uint32_t rq_fs_values[] = {SIZE_2K, SIZE_4K, SIZE_8K, END};
 597         uint32_t rq_mb_values[] = {SIZE_2K, SIZE_4K, SIZE_8K, END};
 598         uint32_t lso_capable_values[] = {0, 1, END};
 599         uint32_t fm_caps_values[] = {DDI_FM_NOT_CAPABLE, OCE_FM_CAPABILITY,
 600             END};
 601         uint32_t tx_rt_values[] = {END};
 602         uint32_t tx_reclaim_values[] = {END};
 603         uint32_t rx_ppi_values[] = {END};
 604         uint32_t rx_rings_values[] = {END};
 605         uint32_t rx_group_values[] = {END};
 606         uint32_t tx_rings_values[] = {END};
 607         uint32_t log_level_values[] = {END};
 608 
 609         /* non tunables  */
 610         dev->rx_ring_size = OCE_DEFAULT_RX_RING_SIZE;
 611 
 612         /* configurable parameters */
 613         dev->flow_control = oce_get_prop(dev, (char *)flow_control, OCE_FC_NONE,
 614             OCE_DEFAULT_FLOW_CONTROL, OCE_DEFAULT_FLOW_CONTROL, fc_values);
 615 
 616         dev->mtu = oce_get_prop(dev, (char *)mtu_prop_name, OCE_MIN_MTU,
 617             OCE_MAX_MTU, OCE_MIN_MTU, mtu_values);
 618 
 619         dev->tx_ring_size = oce_get_prop(dev, (char *)tx_ring_size_name,
 620             SIZE_256, SIZE_2K, OCE_DEFAULT_TX_RING_SIZE, tx_rs_values);
 621 
 622         dev->tx_bcopy_limit = oce_get_prop(dev, (char *)tx_bcopy_limit_name,
 623             SIZE_128, SIZE_2K, OCE_DEFAULT_TX_BCOPY_LIMIT, tx_bcl_values);
 624 
 625         dev->rx_bcopy_limit = oce_get_prop(dev, (char *)rx_bcopy_limit_name,
 626             SIZE_128, SIZE_2K, OCE_DEFAULT_RX_BCOPY_LIMIT, rx_bcl_values);
 627 
 628         dev->rq_frag_size = oce_get_prop(dev, (char *)rx_frag_size_name,
 629             SIZE_2K, SIZE_8K, OCE_RQ_BUF_SIZE, rq_fs_values);
 630 
 631         dev->rq_max_bufs = oce_get_prop(dev, (char *)rx_max_bufs_name, SIZE_2K,
 632             SIZE_8K, OCE_RQ_NUM_BUFFERS, rq_mb_values);
 633 
 634         dev->lso_capable = oce_get_prop(dev, (char *)lso_capable_name, 0,
 635             1, 1, lso_capable_values);
 636 
 637         dev->fm_caps = oce_get_prop(dev, (char *)fm_cap_name,
 638             DDI_FM_NOT_CAPABLE, OCE_FM_CAPABILITY, OCE_FM_CAPABILITY,
 639             fm_caps_values);
 640 
 641         dev->tx_reclaim_threshold = oce_get_prop(dev,
 642             (char *)tx_reclaim_threshold_name, 0, dev->tx_ring_size/2,
 643             OCE_DEFAULT_TX_RECLAIM_THRESHOLD, tx_rt_values);
 644 
 645         dev->tx_reclaim = oce_get_prop(dev, (char *)tx_reclaim, 1,
 646             dev->tx_reclaim_threshold, dev->tx_reclaim_threshold,
 647             tx_reclaim_values);
 648 
 649         dev->rx_pkt_per_intr = oce_get_prop(dev, (char *)rx_pkt_per_intr_name,
 650             1, dev->rx_ring_size/2, OCE_DEFAULT_RX_PKTS_PER_INTR,
 651             rx_ppi_values);
 652 
 653         dev->rx_rings = oce_get_prop(dev, (char *)rx_rings_name,
 654             OCE_MIN_RQ, OCE_MAX_RQ, OCE_DEFAULT_RQS, rx_rings_values);
 655 
 656         dev->rx_rings_per_group = oce_get_prop(dev, (char *)rx_group_name,
 657             OCE_MIN_RING_PER_GROUP, OCE_MAX_RING_PER_GROUP,
 658             OCE_DEF_RING_PER_GROUP, rx_group_values);
 659 
 660         dev->tx_rings = oce_get_prop(dev, (char *)tx_rings_name,
 661             OCE_MIN_WQ, OCE_MAX_WQ, OCE_DEFAULT_WQS, tx_rings_values);
 662 
 663         log_level = oce_get_prop(dev, (char *)log_level_name, 0,
 664             OCE_MAX_LOG_SETTINGS, OCE_DEFAULT_LOG_SETTINGS, log_level_values);
 665 
 666         severity = (uint16_t)(log_level & 0xffff);
 667         mod_mask = (uint16_t)(log_level >> 16);
 668         if (mod_mask > MOD_ISR) {
 669                 mod_mask = 0;
 670         }
 671         if (severity > CE_IGNORE) {
 672                 severity = 0;
 673         }
 674 
 675         dev->mod_mask = mod_mask;
 676         dev->severity = severity;
 677 } /* oce_get_params */
 678 
 679 static int
 680 oce_get_prop(struct oce_dev *dev, char *propname, int minval, int maxval,
 681     int defval, uint32_t *values)
 682 {
 683         int value = 0;
 684         int i = 0;
 685 
 686         value = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
 687             DDI_PROP_DONTPASS, propname, defval);
 688 
 689         if (value > maxval)
 690                 value = maxval;
 691 
 692         if (value < minval)
 693                 value = minval;
 694 
 695         while (values[i] != 0xdeadface) {
 696                 if (values[i] == value) {
 697                         break;
 698                 }
 699                 i++;
 700         }
 701 
 702         if ((i != 0) && (values[i] == 0xdeadface)) {
 703                 value = defval;
 704         }
 705 
 706         return (value);
 707 }
 708 
 709 
 710 static void oce_reset_wd_timer(struct oce_dev *dev)
 711 {
 712         mutex_enter(&dev->wd_lock);
 713         if (dev->wd_enable) {
 714                 oce_set_wd_timer(dev);
 715         }
 716         mutex_exit(&dev->wd_lock);
 717 }
 718 
 719 static void oce_wd_timer(void *arg)
 720 {
 721         struct oce_dev *dev = (struct oce_dev *)arg;
 722 
 723         if (!LANCER_CHIP(dev)) {
 724                 if (oce_check_ue(dev)) {
 725                         /* disable the watchdog and clean-up the interrupts */
 726                         oce_disable_wd_timer(dev);
 727                         mutex_enter(&dev->dev_lock);
 728                         (void) oce_di(dev);
 729                         ddi_fm_service_impact(dev->dip, DDI_SERVICE_LOST);
 730                         mutex_exit(&dev->dev_lock);
 731                         return;
 732                 }
 733         }
 734 
 735         if (oce_tx_stall_check(dev)) {
 736                 oce_log(dev, CE_NOTE, MOD_CONFIG, "Tx Stall Detected at %lu",
 737                     ddi_get_lbolt());
 738         }
 739         /* restart the watch dog timer */
 740         oce_reset_wd_timer(dev);
 741 }
 742 
 743 static void
 744 oce_set_wd_timer(struct oce_dev *dev)
 745 {
 746         dev->wd_id =
 747             timeout(oce_wd_timer, (void *) dev, drv_usectohz(1000000));
 748 }
 749 
 750 void
 751 oce_enable_wd_timer(struct oce_dev *dev)
 752 {
 753 
 754         mutex_enter(&dev->wd_lock);
 755         if (!dev->wd_enable) {
 756                 dev->wd_enable = B_TRUE;
 757                 oce_set_wd_timer(dev);
 758         }
 759         mutex_exit(&dev->wd_lock);
 760 }
 761 
 762 void
 763 oce_disable_wd_timer(struct oce_dev *dev)
 764 {
 765         timeout_id_t wd_id;
 766         mutex_enter(&dev->wd_lock);
 767         dev->wd_enable = B_FALSE;
 768         wd_id = dev->wd_id;
 769         mutex_exit(&dev->wd_lock);
 770         if (wd_id != 0) {
 771                 (void) untimeout(wd_id);
 772                 dev->wd_id = 0;
 773         }
 774 }