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 /* Copyright © 2003-2011 Emulex. All rights reserved. */
23
24 /*
25 * Copyright (c) 2018, Joyent, Inc.
26 */
27
28 /*
29 * Source file containing the implementation of the driver entry points
30 * and related helper functions
31 */
32
33 #include <oce_impl.h>
34 #include <oce_ioctl.h>
35
36 /* array of properties supported by this driver */
37 char *oce_priv_props[] = {
38 "_tx_ring_size",
39 "_tx_bcopy_limit",
40 "_rx_ring_size",
41 "_rx_bcopy_limit",
42 NULL
43 };
44
45 extern int pow10[];
46
47 /* ---[ static function declarations ]----------------------------------- */
48 static int oce_set_priv_prop(struct oce_dev *dev, const char *name,
49 uint_t size, const void *val);
50
51 static int oce_get_priv_prop(struct oce_dev *dev, const char *name,
52 uint_t size, void *val);
53
54 /* ---[ GLD entry points ]----------------------------------------------- */
55 int
oce_m_start(void * arg)56 oce_m_start(void *arg)
57 {
58 struct oce_dev *dev = arg;
59 int ret;
60
61 mutex_enter(&dev->dev_lock);
62
63 if (dev->state & STATE_MAC_STARTED) {
64 mutex_exit(&dev->dev_lock);
65 return (0);
66 }
67
68 if (dev->suspended) {
69 mutex_exit(&dev->dev_lock);
70 return (EIO);
71 }
72 ret = oce_start(dev);
73 if (ret != DDI_SUCCESS) {
74 mutex_exit(&dev->dev_lock);
75 return (EIO);
76 }
77
78 dev->state |= STATE_MAC_STARTED;
79 mutex_exit(&dev->dev_lock);
80
81
82 return (DDI_SUCCESS);
83 }
84
85 int
oce_start(struct oce_dev * dev)86 oce_start(struct oce_dev *dev)
87 {
88 int qidx = 0;
89 struct link_status link = {0};
90
91 /* get link status */
92 (void) oce_get_link_status(dev, &link);
93
94 dev->link_status = (link.logical_link_status == NTWK_LOGICAL_LINK_UP) ?
95 LINK_STATE_UP : LINK_STATE_DOWN;
96
97 dev->link_speed = link.qos_link_speed ? link.qos_link_speed * 10 :
98 pow10[link.mac_speed];
99
100 mac_link_update(dev->mac_handle, dev->link_status);
101
102 for (qidx = 0; qidx < dev->nwqs; qidx++) {
103 (void) oce_start_wq(dev->wq[qidx]);
104 }
105 for (qidx = 0; qidx < dev->nrqs; qidx++) {
106 (void) oce_start_rq(dev->rq[qidx]);
107 }
108 (void) oce_start_mq(dev->mq);
109 /* enable interrupts */
110 oce_ei(dev);
111 /* arm the eqs */
112 for (qidx = 0; qidx < dev->neqs; qidx++) {
113 oce_arm_eq(dev, dev->eq[qidx]->eq_id, 0, B_TRUE, B_FALSE);
114 }
115 /* TODO update state */
116 return (DDI_SUCCESS);
117 } /* oce_start */
118
119
120 void
oce_m_stop(void * arg)121 oce_m_stop(void *arg)
122 {
123 struct oce_dev *dev = arg;
124
125 /* disable interrupts */
126
127 mutex_enter(&dev->dev_lock);
128 if (dev->suspended) {
129 mutex_exit(&dev->dev_lock);
130 return;
131 }
132 dev->state |= STATE_MAC_STOPPING;
133 oce_stop(dev);
134 dev->state &= ~(STATE_MAC_STOPPING | STATE_MAC_STARTED);
135 mutex_exit(&dev->dev_lock);
136 }
137 /* called with Tx/Rx comp locks held */
138 void
oce_stop(struct oce_dev * dev)139 oce_stop(struct oce_dev *dev)
140 {
141 int qidx;
142 /* disable interrupts */
143 oce_di(dev);
144 for (qidx = 0; qidx < dev->nwqs; qidx++) {
145 mutex_enter(&dev->wq[qidx]->tx_lock);
146 }
147 mutex_enter(&dev->mq->lock);
148 /* complete the pending Tx */
149 for (qidx = 0; qidx < dev->nwqs; qidx++)
150 oce_clean_wq(dev->wq[qidx]);
151 /* Release all the locks */
152 mutex_exit(&dev->mq->lock);
153 for (qidx = 0; qidx < dev->nwqs; qidx++)
154 mutex_exit(&dev->wq[qidx]->tx_lock);
155 if (dev->link_status == LINK_STATE_UP) {
156 dev->link_status = LINK_STATE_UNKNOWN;
157 mac_link_update(dev->mac_handle, dev->link_status);
158 }
159
160 } /* oce_stop */
161
162 int
oce_m_multicast(void * arg,boolean_t add,const uint8_t * mca)163 oce_m_multicast(void *arg, boolean_t add, const uint8_t *mca)
164 {
165 struct oce_dev *dev = (struct oce_dev *)arg;
166 struct ether_addr *mca_drv_list;
167 struct ether_addr mca_hw_list[OCE_MAX_MCA];
168 uint16_t new_mcnt = dev->num_mca;
169 int ret;
170 int i;
171
172 /* check the address */
173 if ((mca[0] & 0x1) == 0) {
174 return (EINVAL);
175 }
176 /* Allocate the local array for holding the addresses temporarily */
177 bzero(&mca_hw_list, sizeof (mca_hw_list));
178 mca_drv_list = &dev->multi_cast[0];
179
180 DEV_LOCK(dev);
181 if (add) {
182 /* check if we exceeded hw max supported */
183 if (new_mcnt < OCE_MAX_MCA) {
184 /* copy entire dev mca to the mbx */
185 bcopy((void*)mca_drv_list,
186 (void*)mca_hw_list,
187 (dev->num_mca * sizeof (struct ether_addr)));
188 /* Append the new one to local list */
189 bcopy(mca, &mca_hw_list[dev->num_mca],
190 sizeof (struct ether_addr));
191 }
192 new_mcnt++;
193 } else {
194 struct ether_addr *hwlistp = &mca_hw_list[0];
195 for (i = 0; i < dev->num_mca; i++) {
196 /* copy only if it does not match */
197 if (bcmp((mca_drv_list + i), mca, ETHERADDRL)) {
198 bcopy(mca_drv_list + i, hwlistp,
199 ETHERADDRL);
200 hwlistp++;
201 } else {
202 new_mcnt--;
203 }
204 }
205 }
206
207 if (dev->suspended) {
208 goto finish;
209 }
210 if (new_mcnt > OCE_MAX_MCA) {
211 ret = oce_set_multicast_table(dev, dev->if_id, &mca_hw_list[0],
212 OCE_MAX_MCA, B_TRUE);
213 } else {
214 ret = oce_set_multicast_table(dev, dev->if_id,
215 &mca_hw_list[0], new_mcnt, B_FALSE);
216 }
217 if (ret != 0) {
218 oce_log(dev, CE_WARN, MOD_CONFIG,
219 "mcast %s fails", add ? "ADD" : "DEL");
220 DEV_UNLOCK(dev);
221 return (EIO);
222 }
223 /*
224 * Copy the local structure to dev structure
225 */
226 finish:
227 if (new_mcnt && new_mcnt <= OCE_MAX_MCA) {
228 bcopy(mca_hw_list, mca_drv_list,
229 new_mcnt * sizeof (struct ether_addr));
230
231 dev->num_mca = (uint16_t)new_mcnt;
232 }
233 DEV_UNLOCK(dev);
234 oce_log(dev, CE_NOTE, MOD_CONFIG,
235 "mcast %s, addr=%02x:%02x:%02x:%02x:%02x:%02x, num_mca=%d",
236 add ? "ADD" : "DEL",
237 mca[0], mca[1], mca[2], mca[3], mca[4], mca[5],
238 dev->num_mca);
239 return (0);
240 } /* oce_m_multicast */
241
242 int
oce_m_unicast(void * arg,const uint8_t * uca)243 oce_m_unicast(void *arg, const uint8_t *uca)
244 {
245 struct oce_dev *dev = arg;
246 int ret;
247
248 DEV_LOCK(dev);
249 if (dev->suspended) {
250 bcopy(uca, dev->unicast_addr, ETHERADDRL);
251 dev->num_smac = 0;
252 DEV_UNLOCK(dev);
253 return (DDI_SUCCESS);
254 }
255
256 /* Delete previous one and add new one */
257 ret = oce_del_mac(dev, dev->if_id, &dev->pmac_id);
258 if (ret != DDI_SUCCESS) {
259 DEV_UNLOCK(dev);
260 return (EIO);
261 }
262 dev->num_smac = 0;
263 bzero(dev->unicast_addr, ETHERADDRL);
264
265 /* Set the New MAC addr earlier is no longer valid */
266 ret = oce_add_mac(dev, dev->if_id, uca, &dev->pmac_id);
267 if (ret != DDI_SUCCESS) {
268 DEV_UNLOCK(dev);
269 return (EIO);
270 }
271 bcopy(uca, dev->unicast_addr, ETHERADDRL);
272 dev->num_smac = 1;
273 DEV_UNLOCK(dev);
274 return (ret);
275 } /* oce_m_unicast */
276
277 /*
278 * Hashing policy for load balancing over the set of TX rings
279 * available to the driver.
280 */
281 mblk_t *
oce_m_send(void * arg,mblk_t * mp)282 oce_m_send(void *arg, mblk_t *mp)
283 {
284 struct oce_dev *dev = arg;
285 mblk_t *nxt_pkt;
286 mblk_t *rmp = NULL;
287 struct oce_wq *wq;
288
289 DEV_LOCK(dev);
290 if (dev->suspended || !(dev->state & STATE_MAC_STARTED)) {
291 DEV_UNLOCK(dev);
292 freemsg(mp);
293 return (NULL);
294 }
295 DEV_UNLOCK(dev);
296 /*
297 * Hash to pick a wq
298 */
299 wq = oce_get_wq(dev, mp);
300
301 while (mp != NULL) {
302 /* Save the Pointer since mp will be freed in case of copy */
303 nxt_pkt = mp->b_next;
304 mp->b_next = NULL;
305 /* Hardcode wq since we have only one */
306 rmp = oce_send_packet(wq, mp);
307 if (rmp != NULL) {
308 /* reschedule Tx */
309 wq->resched = B_TRUE;
310 oce_arm_cq(dev, wq->cq->cq_id, 0, B_TRUE);
311 /* restore the chain */
312 rmp->b_next = nxt_pkt;
313 break;
314 }
315 mp = nxt_pkt;
316 }
317 return (rmp);
318 } /* oce_send */
319
320 boolean_t
oce_m_getcap(void * arg,mac_capab_t cap,void * data)321 oce_m_getcap(void *arg, mac_capab_t cap, void *data)
322 {
323 struct oce_dev *dev = arg;
324 boolean_t ret = B_TRUE;
325 switch (cap) {
326
327 case MAC_CAPAB_HCKSUM: {
328 uint32_t *csum_flags = u32ptr(data);
329 *csum_flags = HCKSUM_ENABLE |
330 HCKSUM_INET_FULL_V4 |
331 HCKSUM_IPHDRCKSUM;
332 break;
333 }
334 case MAC_CAPAB_LSO: {
335 mac_capab_lso_t *mcap_lso = (mac_capab_lso_t *)data;
336 if (dev->lso_capable) {
337 mcap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
338 mcap_lso->lso_basic_tcp_ipv4.lso_max = OCE_LSO_MAX_SIZE;
339 } else {
340 ret = B_FALSE;
341 }
342 break;
343 }
344 default:
345 ret = B_FALSE;
346 break;
347 }
348 return (ret);
349 } /* oce_m_getcap */
350
351 int
oce_m_setprop(void * arg,const char * name,mac_prop_id_t id,uint_t size,const void * val)352 oce_m_setprop(void *arg, const char *name, mac_prop_id_t id,
353 uint_t size, const void *val)
354 {
355 struct oce_dev *dev = arg;
356 int ret = 0;
357
358 DEV_LOCK(dev);
359 switch (id) {
360 case MAC_PROP_MTU: {
361 uint32_t mtu;
362
363 bcopy(val, &mtu, sizeof (uint32_t));
364
365 if (dev->mtu == mtu) {
366 ret = 0;
367 break;
368 }
369
370 if (mtu != OCE_MIN_MTU && mtu != OCE_MAX_MTU) {
371 ret = EINVAL;
372 break;
373 }
374
375 ret = mac_maxsdu_update(dev->mac_handle, mtu);
376 if (0 == ret) {
377 dev->mtu = mtu;
378 break;
379 }
380 break;
381 }
382
383 case MAC_PROP_FLOWCTRL: {
384 link_flowctrl_t flowctrl;
385 uint32_t fc = 0;
386
387 bcopy(val, &flowctrl, sizeof (link_flowctrl_t));
388
389 switch (flowctrl) {
390 case LINK_FLOWCTRL_NONE:
391 fc = 0;
392 break;
393
394 case LINK_FLOWCTRL_RX:
395 fc = OCE_FC_RX;
396 break;
397
398 case LINK_FLOWCTRL_TX:
399 fc = OCE_FC_TX;
400 break;
401
402 case LINK_FLOWCTRL_BI:
403 fc = OCE_FC_RX | OCE_FC_TX;
404 break;
405 default:
406 ret = EINVAL;
407 break;
408 } /* switch flowctrl */
409
410 if (ret)
411 break;
412
413 if (fc == dev->flow_control)
414 break;
415
416 if (dev->suspended) {
417 dev->flow_control = fc;
418 break;
419 }
420 /* call to set flow control */
421 ret = oce_set_flow_control(dev, fc);
422 /* store the new fc setting on success */
423 if (ret == 0) {
424 dev->flow_control = fc;
425 }
426 break;
427 }
428
429 case MAC_PROP_PRIVATE:
430 ret = oce_set_priv_prop(dev, name, size, val);
431 break;
432
433 default:
434 ret = ENOTSUP;
435 break;
436 } /* switch id */
437
438 DEV_UNLOCK(dev);
439 return (ret);
440 } /* oce_m_setprop */
441
442 int
oce_m_getprop(void * arg,const char * name,mac_prop_id_t id,uint_t size,void * val)443 oce_m_getprop(void *arg, const char *name, mac_prop_id_t id,
444 uint_t size, void *val)
445 {
446 struct oce_dev *dev = arg;
447 uint32_t ret = 0;
448
449 switch (id) {
450 case MAC_PROP_ADV_10GFDX_CAP:
451 case MAC_PROP_EN_10GFDX_CAP:
452 *(uint8_t *)val = 0x01;
453 break;
454
455 case MAC_PROP_DUPLEX: {
456 uint32_t *mode = (uint32_t *)val;
457
458 ASSERT(size >= sizeof (link_duplex_t));
459 if (dev->state & STATE_MAC_STARTED)
460 *mode = LINK_DUPLEX_FULL;
461 else
462 *mode = LINK_DUPLEX_UNKNOWN;
463 break;
464 }
465
466 case MAC_PROP_SPEED: {
467 uint64_t *speed = (uint64_t *)val;
468 struct link_status link = {0};
469
470 ASSERT(size >= sizeof (uint64_t));
471 *speed = 0;
472
473 if (dev->state & STATE_MAC_STARTED) {
474 if (dev->link_speed < 0) {
475 (void) oce_get_link_status(dev, &link);
476 dev->link_speed = link.qos_link_speed ?
477 link.qos_link_speed * 10 :
478 pow10[link.mac_speed];
479 }
480
481 *speed = dev->link_speed * 1000000ull;
482 }
483 break;
484 }
485
486 case MAC_PROP_FLOWCTRL: {
487 link_flowctrl_t *fc = (link_flowctrl_t *)val;
488
489 ASSERT(size >= sizeof (link_flowctrl_t));
490 if (dev->flow_control & OCE_FC_TX &&
491 dev->flow_control & OCE_FC_RX)
492 *fc = LINK_FLOWCTRL_BI;
493 else if (dev->flow_control == OCE_FC_TX)
494 *fc = LINK_FLOWCTRL_TX;
495 else if (dev->flow_control == OCE_FC_RX)
496 *fc = LINK_FLOWCTRL_RX;
497 else if (dev->flow_control == 0)
498 *fc = LINK_FLOWCTRL_NONE;
499 else
500 ret = EINVAL;
501 break;
502 }
503
504 case MAC_PROP_PRIVATE:
505 ret = oce_get_priv_prop(dev, name, size, val);
506 break;
507
508 default:
509 ret = ENOTSUP;
510 break;
511 } /* switch id */
512 return (ret);
513 } /* oce_m_getprop */
514
515 void
oce_m_propinfo(void * arg,const char * name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)516 oce_m_propinfo(void *arg, const char *name, mac_prop_id_t pr_num,
517 mac_prop_info_handle_t prh)
518 {
519 _NOTE(ARGUNUSED(arg));
520
521 switch (pr_num) {
522 case MAC_PROP_AUTONEG:
523 case MAC_PROP_EN_AUTONEG:
524 case MAC_PROP_ADV_1000FDX_CAP:
525 case MAC_PROP_EN_1000FDX_CAP:
526 case MAC_PROP_ADV_1000HDX_CAP:
527 case MAC_PROP_EN_1000HDX_CAP:
528 case MAC_PROP_ADV_100FDX_CAP:
529 case MAC_PROP_EN_100FDX_CAP:
530 case MAC_PROP_ADV_100HDX_CAP:
531 case MAC_PROP_EN_100HDX_CAP:
532 case MAC_PROP_ADV_10FDX_CAP:
533 case MAC_PROP_EN_10FDX_CAP:
534 case MAC_PROP_ADV_10HDX_CAP:
535 case MAC_PROP_EN_10HDX_CAP:
536 case MAC_PROP_ADV_100T4_CAP:
537 case MAC_PROP_EN_100T4_CAP:
538 case MAC_PROP_ADV_10GFDX_CAP:
539 case MAC_PROP_EN_10GFDX_CAP:
540 case MAC_PROP_SPEED:
541 case MAC_PROP_DUPLEX:
542 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
543 break;
544
545 case MAC_PROP_MTU:
546 mac_prop_info_set_range_uint32(prh, OCE_MIN_MTU, OCE_MAX_MTU);
547 break;
548
549 case MAC_PROP_PRIVATE: {
550 char valstr[64];
551 int value;
552
553 if (strcmp(name, "_tx_ring_size") == 0) {
554 value = OCE_DEFAULT_TX_RING_SIZE;
555 } else if (strcmp(name, "_rx_ring_size") == 0) {
556 value = OCE_DEFAULT_RX_RING_SIZE;
557 } else {
558 return;
559 }
560
561 (void) snprintf(valstr, sizeof (valstr), "%d", value);
562 mac_prop_info_set_default_str(prh, valstr);
563 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
564 break;
565 }
566 }
567 } /* oce_m_propinfo */
568
569 /*
570 * function to handle dlpi streams message from GLDv3 mac layer
571 */
572 void
oce_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)573 oce_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
574 {
575 struct oce_dev *dev = arg;
576 struct iocblk *iocp;
577 int cmd;
578 uint32_t payload_length;
579 int ret;
580
581 iocp = (struct iocblk *)voidptr(mp->b_rptr);
582 iocp->ioc_error = 0;
583 cmd = iocp->ioc_cmd;
584
585 DEV_LOCK(dev);
586 if (dev->suspended) {
587 miocnak(wq, mp, 0, EINVAL);
588 DEV_UNLOCK(dev);
589 return;
590 }
591 DEV_UNLOCK(dev);
592
593 switch (cmd) {
594
595 case OCE_ISSUE_MBOX: {
596 ret = oce_issue_mbox(dev, wq, mp, &payload_length);
597 miocack(wq, mp, payload_length, ret);
598 break;
599 }
600 case OCE_QUERY_DRIVER_DATA: {
601 struct oce_driver_query *drv_query =
602 (struct oce_driver_query *)(void *)mp->b_cont->b_rptr;
603
604 /* if the driver version does not match bail */
605 if (drv_query->version != OCN_VERSION_SUPPORTED) {
606 oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
607 "One Connect version mismatch");
608 miocnak(wq, mp, 0, ENOTSUP);
609 break;
610 }
611
612 /* fill the return values */
613 bcopy(OCE_MOD_NAME, drv_query->driver_name,
614 (sizeof (OCE_MOD_NAME) > 32) ?
615 31 : sizeof (OCE_MOD_NAME));
616 drv_query->driver_name[31] = '\0';
617
618 bcopy(OCE_VERSION, drv_query->driver_version,
619 (sizeof (OCE_VERSION) > 32) ? 31 :
620 sizeof (OCE_VERSION));
621 drv_query->driver_version[31] = '\0';
622
623 if (dev->num_smac == 0) {
624 drv_query->num_smac = 1;
625 bcopy(dev->mac_addr, drv_query->smac_addr[0],
626 ETHERADDRL);
627 } else {
628 drv_query->num_smac = dev->num_smac;
629 bcopy(dev->unicast_addr, drv_query->smac_addr[0],
630 ETHERADDRL);
631 }
632
633 bcopy(dev->mac_addr, drv_query->pmac_addr, ETHERADDRL);
634
635 payload_length = sizeof (struct oce_driver_query);
636 miocack(wq, mp, payload_length, 0);
637 break;
638 }
639
640 default:
641 miocnak(wq, mp, 0, ENOTSUP);
642 break;
643 }
644 } /* oce_m_ioctl */
645
646 int
oce_m_promiscuous(void * arg,boolean_t enable)647 oce_m_promiscuous(void *arg, boolean_t enable)
648 {
649 struct oce_dev *dev = arg;
650 int ret = 0;
651
652 DEV_LOCK(dev);
653
654 if (dev->promisc == enable) {
655 DEV_UNLOCK(dev);
656 return (ret);
657 }
658
659 if (dev->suspended) {
660 /* remember the setting */
661 dev->promisc = enable;
662 DEV_UNLOCK(dev);
663 return (ret);
664 }
665
666 ret = oce_set_promiscuous(dev, enable);
667 if (ret == DDI_SUCCESS)
668 dev->promisc = enable;
669 DEV_UNLOCK(dev);
670 return (ret);
671 } /* oce_m_promiscuous */
672
673 /*
674 * function to set a private property.
675 * Called from the set_prop GLD entry point
676 *
677 * dev - sofware handle to the device
678 * name - string containing the property name
679 * size - length of the string in name
680 * val - pointer to a location where the value to set is stored
681 *
682 * return EINVAL => invalid value in val 0 => success
683 */
684 static int
oce_set_priv_prop(struct oce_dev * dev,const char * name,uint_t size,const void * val)685 oce_set_priv_prop(struct oce_dev *dev, const char *name,
686 uint_t size, const void *val)
687 {
688 int ret = ENOTSUP;
689 long result;
690
691 _NOTE(ARGUNUSED(size));
692
693 if (NULL == val) {
694 ret = EINVAL;
695 return (ret);
696 }
697
698 if (strcmp(name, "_tx_bcopy_limit") == 0) {
699 (void) ddi_strtol(val, (char **)NULL, 0, &result);
700 if (result <= OCE_WQ_BUF_SIZE) {
701 if (result != dev->tx_bcopy_limit)
702 dev->tx_bcopy_limit = (uint32_t)result;
703 ret = 0;
704 } else {
705 ret = EINVAL;
706 }
707 }
708 if (strcmp(name, "_rx_bcopy_limit") == 0) {
709 (void) ddi_strtol(val, (char **)NULL, 0, &result);
710 if (result <= OCE_RQ_BUF_SIZE) {
711 if (result != dev->rx_bcopy_limit)
712 dev->rx_bcopy_limit = (uint32_t)result;
713 ret = 0;
714 } else {
715 ret = EINVAL;
716 }
717 }
718
719 return (ret);
720 } /* oce_set_priv_prop */
721
722 /*
723 * function to get the value of a private property. Called from get_prop
724 *
725 * dev - software handle to the device
726 * name - string containing the property name
727 * size - length of the string contained name
728 * val - [OUT] pointer to the location where the result is returned
729 *
730 * return EINVAL => invalid request 0 => success
731 */
732 static int
oce_get_priv_prop(struct oce_dev * dev,const char * name,uint_t size,void * val)733 oce_get_priv_prop(struct oce_dev *dev, const char *name,
734 uint_t size, void *val)
735 {
736 int value;
737
738 if (strcmp(name, "_tx_ring_size") == 0) {
739 value = dev->tx_ring_size;
740 } else if (strcmp(name, "_tx_bcopy_limit") == 0) {
741 value = dev->tx_bcopy_limit;
742 } else if (strcmp(name, "_rx_ring_size") == 0) {
743 value = dev->rx_ring_size;
744 } else if (strcmp(name, "_rx_bcopy_limit") == 0) {
745 value = dev->rx_bcopy_limit;
746 } else {
747 return (ENOTSUP);
748 }
749
750 (void) snprintf(val, size, "%d", value);
751 return (0);
752 } /* oce_get_priv_prop */
753