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