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 }