xref: /titanic_44/usr/src/uts/common/io/ixgbe/ixgbe_transceiver.c (revision 48a4016cae8aa2b8b3d8b258eb22e0c781912bed)
1*48a4016cSRobert Mustacchi /*
2*48a4016cSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*48a4016cSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*48a4016cSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*48a4016cSRobert Mustacchi  * 1.0 of the CDDL.
6*48a4016cSRobert Mustacchi  *
7*48a4016cSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*48a4016cSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*48a4016cSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*48a4016cSRobert Mustacchi  */
11*48a4016cSRobert Mustacchi 
12*48a4016cSRobert Mustacchi /*
13*48a4016cSRobert Mustacchi  * Copyright (c) 2017, Joyent, Inc.
14*48a4016cSRobert Mustacchi  */
15*48a4016cSRobert Mustacchi 
16*48a4016cSRobert Mustacchi /*
17*48a4016cSRobert Mustacchi  * Routines to get access to the phy and transceiver that require routines and
18*48a4016cSRobert Mustacchi  * definitions that aren't part of the common ixgbe API.
19*48a4016cSRobert Mustacchi  */
20*48a4016cSRobert Mustacchi 
21*48a4016cSRobert Mustacchi #include "ixgbe_sw.h"
22*48a4016cSRobert Mustacchi #include "ixgbe_phy.h"
23*48a4016cSRobert Mustacchi 
24*48a4016cSRobert Mustacchi static int
ixgbe_transceiver_is_8472(ixgbe_t * ixgbe,boolean_t * valp)25*48a4016cSRobert Mustacchi ixgbe_transceiver_is_8472(ixgbe_t *ixgbe, boolean_t *valp)
26*48a4016cSRobert Mustacchi {
27*48a4016cSRobert Mustacchi 	int32_t ret;
28*48a4016cSRobert Mustacchi 	uint8_t rev, swap;
29*48a4016cSRobert Mustacchi 	struct ixgbe_hw *hw = &ixgbe->hw;
30*48a4016cSRobert Mustacchi 
31*48a4016cSRobert Mustacchi 	ASSERT(MUTEX_HELD(&ixgbe->gen_lock));
32*48a4016cSRobert Mustacchi 	if (hw->phy.ops.read_i2c_eeprom == NULL)
33*48a4016cSRobert Mustacchi 		return (ENOTSUP);
34*48a4016cSRobert Mustacchi 
35*48a4016cSRobert Mustacchi 	ret = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_SFF_8472_COMP, &rev);
36*48a4016cSRobert Mustacchi 	if (ret != 0)
37*48a4016cSRobert Mustacchi 		return (EIO);
38*48a4016cSRobert Mustacchi 
39*48a4016cSRobert Mustacchi 	ret = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_SFF_8472_SWAP, &swap);
40*48a4016cSRobert Mustacchi 	if (ret != 0)
41*48a4016cSRobert Mustacchi 		return (EIO);
42*48a4016cSRobert Mustacchi 
43*48a4016cSRobert Mustacchi 	if (swap & IXGBE_SFF_ADDRESSING_MODE) {
44*48a4016cSRobert Mustacchi 		ixgbe_log(ixgbe, "transceiver requires unsupported address "
45*48a4016cSRobert Mustacchi 		    "change for page 0xa2. Access will only be allowed to "
46*48a4016cSRobert Mustacchi 		    "page 0xa0.");
47*48a4016cSRobert Mustacchi 	}
48*48a4016cSRobert Mustacchi 
49*48a4016cSRobert Mustacchi 	if (rev == IXGBE_SFF_SFF_8472_UNSUP ||
50*48a4016cSRobert Mustacchi 	    (swap & IXGBE_SFF_ADDRESSING_MODE)) {
51*48a4016cSRobert Mustacchi 		*valp = B_FALSE;
52*48a4016cSRobert Mustacchi 	} else {
53*48a4016cSRobert Mustacchi 		*valp = B_TRUE;
54*48a4016cSRobert Mustacchi 	}
55*48a4016cSRobert Mustacchi 
56*48a4016cSRobert Mustacchi 	return (0);
57*48a4016cSRobert Mustacchi }
58*48a4016cSRobert Mustacchi 
59*48a4016cSRobert Mustacchi /*
60*48a4016cSRobert Mustacchi  * Note, we presume that the mac perimeter is held during these calls. As such,
61*48a4016cSRobert Mustacchi  * we rely on that for guaranteeing that only one thread is calling the i2c
62*48a4016cSRobert Mustacchi  * routines at any time.
63*48a4016cSRobert Mustacchi  */
64*48a4016cSRobert Mustacchi int
ixgbe_transceiver_info(void * arg,uint_t id,mac_transceiver_info_t * infop)65*48a4016cSRobert Mustacchi ixgbe_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop)
66*48a4016cSRobert Mustacchi {
67*48a4016cSRobert Mustacchi 	ixgbe_t *ixgbe = arg;
68*48a4016cSRobert Mustacchi 	struct ixgbe_hw *hw = &ixgbe->hw;
69*48a4016cSRobert Mustacchi 	boolean_t present, usable;
70*48a4016cSRobert Mustacchi 
71*48a4016cSRobert Mustacchi 	if (id != 0 || infop == NULL)
72*48a4016cSRobert Mustacchi 		return (EINVAL);
73*48a4016cSRobert Mustacchi 
74*48a4016cSRobert Mustacchi 	mutex_enter(&ixgbe->gen_lock);
75*48a4016cSRobert Mustacchi 	if (ixgbe_get_media_type(&ixgbe->hw) == ixgbe_media_type_copper) {
76*48a4016cSRobert Mustacchi 		mutex_exit(&ixgbe->gen_lock);
77*48a4016cSRobert Mustacchi 		return (ENOTSUP);
78*48a4016cSRobert Mustacchi 	}
79*48a4016cSRobert Mustacchi 
80*48a4016cSRobert Mustacchi 	/*
81*48a4016cSRobert Mustacchi 	 * Make sure we have the latest sfp information. This is especially
82*48a4016cSRobert Mustacchi 	 * important if the SFP is removed as that doesn't trigger interrupts in
83*48a4016cSRobert Mustacchi 	 * our current configuration.
84*48a4016cSRobert Mustacchi 	 */
85*48a4016cSRobert Mustacchi 	(void) hw->phy.ops.identify_sfp(hw);
86*48a4016cSRobert Mustacchi 	if (hw->phy.type == ixgbe_phy_none ||
87*48a4016cSRobert Mustacchi 	    (hw->phy.type == ixgbe_phy_unknown &&
88*48a4016cSRobert Mustacchi 	    hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
89*48a4016cSRobert Mustacchi 		present = B_FALSE;
90*48a4016cSRobert Mustacchi 		usable = B_FALSE;
91*48a4016cSRobert Mustacchi 	} else {
92*48a4016cSRobert Mustacchi 		present = B_TRUE;
93*48a4016cSRobert Mustacchi 		usable = hw->phy.type != ixgbe_phy_sfp_unsupported;
94*48a4016cSRobert Mustacchi 	}
95*48a4016cSRobert Mustacchi 
96*48a4016cSRobert Mustacchi 	mutex_exit(&ixgbe->gen_lock);
97*48a4016cSRobert Mustacchi 
98*48a4016cSRobert Mustacchi 	mac_transceiver_info_set_present(infop, present);
99*48a4016cSRobert Mustacchi 	mac_transceiver_info_set_usable(infop, usable);
100*48a4016cSRobert Mustacchi 
101*48a4016cSRobert Mustacchi 	return (0);
102*48a4016cSRobert Mustacchi }
103*48a4016cSRobert Mustacchi 
104*48a4016cSRobert Mustacchi /*
105*48a4016cSRobert Mustacchi  * Note, we presume that the mac perimeter is held during these calls. As such,
106*48a4016cSRobert Mustacchi  * we rely on that for guaranteeing that only one thread is calling the i2c
107*48a4016cSRobert Mustacchi  * routines at any time.
108*48a4016cSRobert Mustacchi  */
109*48a4016cSRobert Mustacchi int
ixgbe_transceiver_read(void * arg,uint_t id,uint_t page,void * bp,size_t nbytes,off_t offset,size_t * nread)110*48a4016cSRobert Mustacchi ixgbe_transceiver_read(void *arg, uint_t id, uint_t page, void *bp,
111*48a4016cSRobert Mustacchi     size_t nbytes, off_t offset, size_t *nread)
112*48a4016cSRobert Mustacchi {
113*48a4016cSRobert Mustacchi 	ixgbe_t *ixgbe = arg;
114*48a4016cSRobert Mustacchi 	struct ixgbe_hw *hw = &ixgbe->hw;
115*48a4016cSRobert Mustacchi 	uint8_t *buf = bp;
116*48a4016cSRobert Mustacchi 	size_t i;
117*48a4016cSRobert Mustacchi 	boolean_t is8472;
118*48a4016cSRobert Mustacchi 
119*48a4016cSRobert Mustacchi 	if (id != 0 || buf == NULL || nbytes == 0 || nread == NULL ||
120*48a4016cSRobert Mustacchi 	    (page != 0xa0 && page != 0xa2) || offset < 0)
121*48a4016cSRobert Mustacchi 		return (EINVAL);
122*48a4016cSRobert Mustacchi 
123*48a4016cSRobert Mustacchi 	/*
124*48a4016cSRobert Mustacchi 	 * Both supported pages have a length of 256 bytes, ensure nothing asks
125*48a4016cSRobert Mustacchi 	 * us to go beyond that.
126*48a4016cSRobert Mustacchi 	 */
127*48a4016cSRobert Mustacchi 	if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) {
128*48a4016cSRobert Mustacchi 		return (EINVAL);
129*48a4016cSRobert Mustacchi 	}
130*48a4016cSRobert Mustacchi 
131*48a4016cSRobert Mustacchi 	mutex_enter(&ixgbe->gen_lock);
132*48a4016cSRobert Mustacchi 	if (ixgbe_get_media_type(&ixgbe->hw) == ixgbe_media_type_copper) {
133*48a4016cSRobert Mustacchi 		mutex_exit(&ixgbe->gen_lock);
134*48a4016cSRobert Mustacchi 		return (ENOTSUP);
135*48a4016cSRobert Mustacchi 	}
136*48a4016cSRobert Mustacchi 
137*48a4016cSRobert Mustacchi 	if (hw->phy.ops.read_i2c_eeprom == NULL) {
138*48a4016cSRobert Mustacchi 		mutex_exit(&ixgbe->gen_lock);
139*48a4016cSRobert Mustacchi 		return (ENOTSUP);
140*48a4016cSRobert Mustacchi 	}
141*48a4016cSRobert Mustacchi 
142*48a4016cSRobert Mustacchi 	if (ixgbe_transceiver_is_8472(ixgbe, &is8472) != 0) {
143*48a4016cSRobert Mustacchi 		mutex_exit(&ixgbe->gen_lock);
144*48a4016cSRobert Mustacchi 		return (EIO);
145*48a4016cSRobert Mustacchi 	}
146*48a4016cSRobert Mustacchi 
147*48a4016cSRobert Mustacchi 	if (!is8472 && page == 0xa2) {
148*48a4016cSRobert Mustacchi 		mutex_exit(&ixgbe->gen_lock);
149*48a4016cSRobert Mustacchi 		return (EINVAL);
150*48a4016cSRobert Mustacchi 	}
151*48a4016cSRobert Mustacchi 
152*48a4016cSRobert Mustacchi 	for (i = 0; i < nbytes; i++, offset++, buf++) {
153*48a4016cSRobert Mustacchi 		int32_t ret;
154*48a4016cSRobert Mustacchi 
155*48a4016cSRobert Mustacchi 		if (page == 0xa0) {
156*48a4016cSRobert Mustacchi 			ret = hw->phy.ops.read_i2c_eeprom(hw, offset, buf);
157*48a4016cSRobert Mustacchi 		} else {
158*48a4016cSRobert Mustacchi 			ret = hw->phy.ops.read_i2c_sff8472(hw, offset, buf);
159*48a4016cSRobert Mustacchi 		}
160*48a4016cSRobert Mustacchi 		if (ret != 0) {
161*48a4016cSRobert Mustacchi 			mutex_exit(&ixgbe->gen_lock);
162*48a4016cSRobert Mustacchi 			return (EIO);
163*48a4016cSRobert Mustacchi 		}
164*48a4016cSRobert Mustacchi 	}
165*48a4016cSRobert Mustacchi 	mutex_exit(&ixgbe->gen_lock);
166*48a4016cSRobert Mustacchi 	*nread = i;
167*48a4016cSRobert Mustacchi 
168*48a4016cSRobert Mustacchi 	return (0);
169*48a4016cSRobert Mustacchi }
170