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