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