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