1 /*
2  * CDDL HEADER START
3  *
4  * Copyright(c) 2007-2009 Intel Corporation. All rights reserved.
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #include "ixgbe_sw.h"
29 
30 /*
31  * Retrieve a value for one of the statistics.
32  */
33 int
34 ixgbe_m_stat(void *arg, uint_t stat, uint64_t *val)
35 {
36 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
37 	struct ixgbe_hw *hw = &ixgbe->hw;
38 	ixgbe_stat_t *ixgbe_ks;
39 	int i;
40 
41 	ixgbe_ks = (ixgbe_stat_t *)ixgbe->ixgbe_ks->ks_data;
42 
43 	mutex_enter(&ixgbe->gen_lock);
44 
45 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
46 		mutex_exit(&ixgbe->gen_lock);
47 		return (ECANCELED);
48 	}
49 
50 	switch (stat) {
51 	case MAC_STAT_IFSPEED:
52 		*val = ixgbe->link_speed * 1000000ull;
53 		break;
54 
55 	case MAC_STAT_MULTIRCV:
56 		ixgbe_ks->mprc.value.ui64 +=
57 		    IXGBE_READ_REG(hw, IXGBE_MPRC);
58 		*val = ixgbe_ks->mprc.value.ui64;
59 		break;
60 
61 	case MAC_STAT_BRDCSTRCV:
62 		ixgbe_ks->bprc.value.ui64 +=
63 		    IXGBE_READ_REG(hw, IXGBE_BPRC);
64 		*val = ixgbe_ks->bprc.value.ui64;
65 		break;
66 
67 	case MAC_STAT_MULTIXMT:
68 		ixgbe_ks->mptc.value.ui64 +=
69 		    IXGBE_READ_REG(hw, IXGBE_MPTC);
70 		*val = ixgbe_ks->mptc.value.ui64;
71 		break;
72 
73 	case MAC_STAT_BRDCSTXMT:
74 		ixgbe_ks->bptc.value.ui64 +=
75 		    IXGBE_READ_REG(hw, IXGBE_BPTC);
76 		*val = ixgbe_ks->bptc.value.ui64;
77 		break;
78 
79 	case MAC_STAT_NORCVBUF:
80 		for (i = 0; i < 8; i++) {
81 			ixgbe_ks->rnbc.value.ui64 +=
82 			    IXGBE_READ_REG(hw, IXGBE_RNBC(i));
83 		}
84 		*val = ixgbe_ks->rnbc.value.ui64;
85 		break;
86 
87 	case MAC_STAT_IERRORS:
88 		ixgbe_ks->crcerrs.value.ui64 +=
89 		    IXGBE_READ_REG(hw, IXGBE_CRCERRS);
90 		ixgbe_ks->illerrc.value.ui64 +=
91 		    IXGBE_READ_REG(hw, IXGBE_ILLERRC);
92 		ixgbe_ks->errbc.value.ui64 +=
93 		    IXGBE_READ_REG(hw, IXGBE_ERRBC);
94 		ixgbe_ks->rlec.value.ui64 +=
95 		    IXGBE_READ_REG(hw, IXGBE_RLEC);
96 		*val = ixgbe_ks->crcerrs.value.ui64 +
97 		    ixgbe_ks->illerrc.value.ui64 +
98 		    ixgbe_ks->errbc.value.ui64 +
99 		    ixgbe_ks->rlec.value.ui64;
100 		break;
101 
102 	case MAC_STAT_RBYTES:
103 		ixgbe_ks->tor.value.ui64 = 0;
104 		for (i = 0; i < 16; i++) {
105 			ixgbe_ks->qbrc[i].value.ui64 +=
106 			    IXGBE_READ_REG(hw, IXGBE_QBRC(i));
107 			ixgbe_ks->tor.value.ui64 +=
108 			    ixgbe_ks->qbrc[i].value.ui64;
109 		}
110 		*val = ixgbe_ks->tor.value.ui64;
111 		break;
112 
113 	case MAC_STAT_OBYTES:
114 		ixgbe_ks->tot.value.ui64 = 0;
115 		for (i = 0; i < 16; i++) {
116 			if (hw->mac.type >= ixgbe_mac_82599EB) {
117 				ixgbe_ks->qbtc[i].value.ui64 +=
118 				    IXGBE_READ_REG(hw, IXGBE_QBTC_L(i));
119 				ixgbe_ks->qbtc[i].value.ui64 += ((uint64_t)
120 				    IXGBE_READ_REG(hw, IXGBE_QBTC_H(i))) << 32;
121 			} else {
122 				ixgbe_ks->qbtc[i].value.ui64 +=
123 				    IXGBE_READ_REG(hw, IXGBE_QBTC(i));
124 			}
125 			ixgbe_ks->tot.value.ui64 +=
126 			    ixgbe_ks->qbtc[i].value.ui64;
127 		}
128 		*val = ixgbe_ks->tot.value.ui64;
129 		break;
130 
131 	case MAC_STAT_IPACKETS:
132 		ixgbe_ks->tpr.value.ui64 +=
133 		    IXGBE_READ_REG(hw, IXGBE_TPR);
134 		*val = ixgbe_ks->tpr.value.ui64;
135 		break;
136 
137 	case MAC_STAT_OPACKETS:
138 		ixgbe_ks->tpt.value.ui64 +=
139 		    IXGBE_READ_REG(hw, IXGBE_TPT);
140 		*val = ixgbe_ks->tpt.value.ui64;
141 		break;
142 
143 	/* RFC 1643 stats */
144 	case ETHER_STAT_FCS_ERRORS:
145 		ixgbe_ks->crcerrs.value.ui64 +=
146 		    IXGBE_READ_REG(hw, IXGBE_CRCERRS);
147 		*val = ixgbe_ks->crcerrs.value.ui64;
148 		break;
149 
150 	case ETHER_STAT_TOOLONG_ERRORS:
151 		ixgbe_ks->roc.value.ui64 +=
152 		    IXGBE_READ_REG(hw, IXGBE_ROC);
153 		*val = ixgbe_ks->roc.value.ui64;
154 		break;
155 
156 	case ETHER_STAT_MACRCV_ERRORS:
157 		ixgbe_ks->crcerrs.value.ui64 +=
158 		    IXGBE_READ_REG(hw, IXGBE_CRCERRS);
159 		ixgbe_ks->illerrc.value.ui64 +=
160 		    IXGBE_READ_REG(hw, IXGBE_ILLERRC);
161 		ixgbe_ks->errbc.value.ui64 +=
162 		    IXGBE_READ_REG(hw, IXGBE_ERRBC);
163 		ixgbe_ks->rlec.value.ui64 +=
164 		    IXGBE_READ_REG(hw, IXGBE_RLEC);
165 		*val = ixgbe_ks->crcerrs.value.ui64 +
166 		    ixgbe_ks->illerrc.value.ui64 +
167 		    ixgbe_ks->errbc.value.ui64 +
168 		    ixgbe_ks->rlec.value.ui64;
169 		break;
170 
171 	/* MII/GMII stats */
172 	case ETHER_STAT_XCVR_ADDR:
173 		/* The Internal PHY's MDI address for each MAC is 1 */
174 		*val = 1;
175 		break;
176 
177 	case ETHER_STAT_XCVR_ID:
178 		*val = hw->phy.id;
179 		break;
180 
181 	case ETHER_STAT_XCVR_INUSE:
182 		switch (ixgbe->link_speed) {
183 		case IXGBE_LINK_SPEED_1GB_FULL:
184 			*val =
185 			    (hw->phy.media_type == ixgbe_media_type_copper) ?
186 			    XCVR_1000T : XCVR_1000X;
187 			break;
188 		case IXGBE_LINK_SPEED_100_FULL:
189 			*val = (hw->phy.media_type == ixgbe_media_type_copper) ?
190 			    XCVR_100T2 : XCVR_100X;
191 			break;
192 		default:
193 			*val = XCVR_NONE;
194 			break;
195 		}
196 		break;
197 
198 	case ETHER_STAT_CAP_1000FDX:
199 		*val = ixgbe->param_1000fdx_cap;
200 		break;
201 
202 	case ETHER_STAT_CAP_100FDX:
203 		*val = ixgbe->param_100fdx_cap;
204 		break;
205 
206 	case ETHER_STAT_CAP_ASMPAUSE:
207 		*val = ixgbe->param_asym_pause_cap;
208 		break;
209 
210 	case ETHER_STAT_CAP_PAUSE:
211 		*val = ixgbe->param_pause_cap;
212 		break;
213 
214 	case ETHER_STAT_CAP_AUTONEG:
215 		*val = ixgbe->param_autoneg_cap;
216 		break;
217 
218 	case ETHER_STAT_ADV_CAP_1000FDX:
219 		*val = ixgbe->param_adv_1000fdx_cap;
220 		break;
221 
222 	case ETHER_STAT_ADV_CAP_100FDX:
223 		*val = ixgbe->param_adv_100fdx_cap;
224 		break;
225 
226 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
227 		*val = ixgbe->param_adv_asym_pause_cap;
228 		break;
229 
230 	case ETHER_STAT_ADV_CAP_PAUSE:
231 		*val = ixgbe->param_adv_pause_cap;
232 		break;
233 
234 	case ETHER_STAT_ADV_CAP_AUTONEG:
235 		*val = hw->mac.autoneg;
236 		break;
237 
238 	case ETHER_STAT_LP_CAP_1000FDX:
239 		*val = ixgbe->param_lp_1000fdx_cap;
240 		break;
241 
242 	case ETHER_STAT_LP_CAP_100FDX:
243 		*val = ixgbe->param_lp_100fdx_cap;
244 		break;
245 
246 	case ETHER_STAT_LP_CAP_ASMPAUSE:
247 		*val = ixgbe->param_lp_asym_pause_cap;
248 		break;
249 
250 	case ETHER_STAT_LP_CAP_PAUSE:
251 		*val = ixgbe->param_lp_pause_cap;
252 		break;
253 
254 	case ETHER_STAT_LP_CAP_AUTONEG:
255 		*val = ixgbe->param_lp_autoneg_cap;
256 		break;
257 
258 	case ETHER_STAT_LINK_ASMPAUSE:
259 		*val = ixgbe->param_asym_pause_cap;
260 		break;
261 
262 	case ETHER_STAT_LINK_PAUSE:
263 		*val = ixgbe->param_pause_cap;
264 		break;
265 
266 	case ETHER_STAT_LINK_AUTONEG:
267 		*val = hw->mac.autoneg;
268 		break;
269 	case ETHER_STAT_LINK_DUPLEX:
270 		*val = LINK_DUPLEX_FULL;
271 		break;
272 
273 	case ETHER_STAT_TOOSHORT_ERRORS:
274 		ixgbe_ks->ruc.value.ui64 +=
275 		    IXGBE_READ_REG(hw, IXGBE_RUC);
276 		*val = ixgbe_ks->ruc.value.ui64;
277 		break;
278 
279 	case ETHER_STAT_CAP_REMFAULT:
280 		*val = ixgbe->param_rem_fault;
281 		break;
282 
283 	case ETHER_STAT_ADV_REMFAULT:
284 		*val = ixgbe->param_adv_rem_fault;
285 		break;
286 
287 	case ETHER_STAT_LP_REMFAULT:
288 		*val = ixgbe->param_lp_rem_fault;
289 		break;
290 
291 	case ETHER_STAT_JABBER_ERRORS:
292 		ixgbe_ks->rjc.value.ui64 +=
293 		    IXGBE_READ_REG(hw, IXGBE_RJC);
294 		*val = ixgbe_ks->rjc.value.ui64;
295 		break;
296 
297 	default:
298 		mutex_exit(&ixgbe->gen_lock);
299 		return (ENOTSUP);
300 	}
301 
302 	mutex_exit(&ixgbe->gen_lock);
303 
304 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK)
305 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_UNAFFECTED);
306 
307 	return (0);
308 }
309 
310 /*
311  * Bring the device out of the reset/quiesced state that it
312  * was in when the interface was registered.
313  */
314 int
315 ixgbe_m_start(void *arg)
316 {
317 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
318 
319 	mutex_enter(&ixgbe->gen_lock);
320 
321 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
322 		mutex_exit(&ixgbe->gen_lock);
323 		return (ECANCELED);
324 	}
325 
326 	if (ixgbe_start(ixgbe) != IXGBE_SUCCESS) {
327 		mutex_exit(&ixgbe->gen_lock);
328 		return (EIO);
329 	}
330 
331 	ixgbe->ixgbe_state |= IXGBE_STARTED;
332 
333 	mutex_exit(&ixgbe->gen_lock);
334 
335 	/*
336 	 * Enable and start the watchdog timer
337 	 */
338 	ixgbe_enable_watchdog_timer(ixgbe);
339 
340 	return (0);
341 }
342 
343 /*
344  * Stop the device and put it in a reset/quiesced state such
345  * that the interface can be unregistered.
346  */
347 void
348 ixgbe_m_stop(void *arg)
349 {
350 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
351 
352 	mutex_enter(&ixgbe->gen_lock);
353 
354 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
355 		mutex_exit(&ixgbe->gen_lock);
356 		return;
357 	}
358 
359 	ixgbe->ixgbe_state &= ~IXGBE_STARTED;
360 
361 	ixgbe_stop(ixgbe);
362 
363 	mutex_exit(&ixgbe->gen_lock);
364 
365 	/*
366 	 * Disable and stop the watchdog timer
367 	 */
368 	ixgbe_disable_watchdog_timer(ixgbe);
369 }
370 
371 /*
372  * Set the promiscuity of the device.
373  */
374 int
375 ixgbe_m_promisc(void *arg, boolean_t on)
376 {
377 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
378 	uint32_t reg_val;
379 	struct ixgbe_hw *hw = &ixgbe->hw;
380 
381 	mutex_enter(&ixgbe->gen_lock);
382 
383 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
384 		mutex_exit(&ixgbe->gen_lock);
385 		return (ECANCELED);
386 	}
387 	reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL);
388 
389 	if (on)
390 		reg_val |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
391 	else
392 		reg_val &= (~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE));
393 
394 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_FCTRL, reg_val);
395 
396 	mutex_exit(&ixgbe->gen_lock);
397 
398 	return (0);
399 }
400 
401 /*
402  * Add/remove the addresses to/from the set of multicast
403  * addresses for which the device will receive packets.
404  */
405 int
406 ixgbe_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr)
407 {
408 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
409 	int result;
410 
411 	mutex_enter(&ixgbe->gen_lock);
412 
413 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
414 		mutex_exit(&ixgbe->gen_lock);
415 		return (ECANCELED);
416 	}
417 
418 	result = (add) ? ixgbe_multicst_add(ixgbe, mcst_addr)
419 	    : ixgbe_multicst_remove(ixgbe, mcst_addr);
420 
421 	mutex_exit(&ixgbe->gen_lock);
422 
423 	return (result);
424 }
425 
426 /*
427  * Pass on M_IOCTL messages passed to the DLD, and support
428  * private IOCTLs for debugging and ndd.
429  */
430 void
431 ixgbe_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
432 {
433 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
434 	struct iocblk *iocp;
435 	enum ioc_reply status;
436 
437 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
438 	iocp->ioc_error = 0;
439 
440 	switch (iocp->ioc_cmd) {
441 	case LB_GET_INFO_SIZE:
442 	case LB_GET_INFO:
443 	case LB_GET_MODE:
444 	case LB_SET_MODE:
445 		status = ixgbe_loopback_ioctl(ixgbe, iocp, mp);
446 		break;
447 
448 	case ND_GET:
449 	case ND_SET:
450 		status = ixgbe_nd_ioctl(ixgbe, q, mp, iocp);
451 		break;
452 
453 	default:
454 		status = IOC_INVAL;
455 		break;
456 	}
457 
458 	/*
459 	 * Decide how to reply
460 	 */
461 	switch (status) {
462 	default:
463 	case IOC_INVAL:
464 		/*
465 		 * Error, reply with a NAK and EINVAL or the specified error
466 		 */
467 		miocnak(q, mp, 0, iocp->ioc_error == 0 ?
468 		    EINVAL : iocp->ioc_error);
469 		break;
470 
471 	case IOC_DONE:
472 		/*
473 		 * OK, reply already sent
474 		 */
475 		break;
476 
477 	case IOC_ACK:
478 		/*
479 		 * OK, reply with an ACK
480 		 */
481 		miocack(q, mp, 0, 0);
482 		break;
483 
484 	case IOC_REPLY:
485 		/*
486 		 * OK, send prepared reply as ACK or NAK
487 		 */
488 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
489 		    M_IOCACK : M_IOCNAK;
490 		qreply(q, mp);
491 		break;
492 	}
493 }
494 
495 /*
496  * Obtain the MAC's capabilities and associated data from
497  * the driver.
498  */
499 boolean_t
500 ixgbe_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
501 {
502 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
503 
504 	switch (cap) {
505 	case MAC_CAPAB_HCKSUM: {
506 		uint32_t *tx_hcksum_flags = cap_data;
507 
508 		/*
509 		 * We advertise our capabilities only if tx hcksum offload is
510 		 * enabled.  On receive, the stack will accept checksummed
511 		 * packets anyway, even if we haven't said we can deliver
512 		 * them.
513 		 */
514 		if (!ixgbe->tx_hcksum_enable)
515 			return (B_FALSE);
516 
517 		*tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
518 		break;
519 	}
520 	case MAC_CAPAB_LSO: {
521 		mac_capab_lso_t *cap_lso = cap_data;
522 
523 		if (ixgbe->lso_enable) {
524 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
525 			cap_lso->lso_basic_tcp_ipv4.lso_max = IXGBE_LSO_MAXLEN;
526 			break;
527 		} else {
528 			return (B_FALSE);
529 		}
530 	}
531 	case MAC_CAPAB_RINGS: {
532 		mac_capab_rings_t *cap_rings = cap_data;
533 
534 		switch (cap_rings->mr_type) {
535 		case MAC_RING_TYPE_RX:
536 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
537 			cap_rings->mr_rnum = ixgbe->num_rx_rings;
538 			cap_rings->mr_gnum = ixgbe->num_rx_groups;
539 			cap_rings->mr_rget = ixgbe_fill_ring;
540 			cap_rings->mr_gget = ixgbe_fill_group;
541 			cap_rings->mr_gaddring = NULL;
542 			cap_rings->mr_gremring = NULL;
543 			break;
544 		case MAC_RING_TYPE_TX:
545 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
546 			cap_rings->mr_rnum = ixgbe->num_tx_rings;
547 			cap_rings->mr_gnum = 0;
548 			cap_rings->mr_rget = ixgbe_fill_ring;
549 			cap_rings->mr_gget = NULL;
550 			break;
551 		default:
552 			break;
553 		}
554 		break;
555 	}
556 	default:
557 		return (B_FALSE);
558 	}
559 	return (B_TRUE);
560 }
561