Merge commit '06307114472bd8aad5ff18ccdb8e25f128ae6652'
[unleashed.git] / kernel / drivers / net / ixgbe / ixgbe_transceiver.c
blob131b43d41817462fa1b9b59d1666ba79e442bcf8
1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright (c) 2017, Joyent, Inc.
17 * Routines to get access to the phy and transceiver that require routines and
18 * definitions that aren't part of the common ixgbe API.
21 #include "ixgbe_sw.h"
22 #include "ixgbe_phy.h"
24 static int
25 ixgbe_transceiver_is_8472(ixgbe_t *ixgbe, boolean_t *valp)
27 int32_t ret;
28 uint8_t rev, swap;
29 struct ixgbe_hw *hw = &ixgbe->hw;
31 ASSERT(MUTEX_HELD(&ixgbe->gen_lock));
32 if (hw->phy.ops.read_i2c_eeprom == NULL)
33 return (ENOTSUP);
35 ret = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_SFF_8472_COMP, &rev);
36 if (ret != 0)
37 return (EIO);
39 ret = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_SFF_8472_SWAP, &swap);
40 if (ret != 0)
41 return (EIO);
43 if (swap & IXGBE_SFF_ADDRESSING_MODE) {
44 ixgbe_log(ixgbe, "transceiver requires unsupported address "
45 "change for page 0xa2. Access will only be allowed to "
46 "page 0xa0.");
49 if (rev == IXGBE_SFF_SFF_8472_UNSUP ||
50 (swap & IXGBE_SFF_ADDRESSING_MODE)) {
51 *valp = B_FALSE;
52 } else {
53 *valp = B_TRUE;
56 return (0);
60 * Note, we presume that the mac perimeter is held during these calls. As such,
61 * we rely on that for guaranteeing that only one thread is calling the i2c
62 * routines at any time.
64 int
65 ixgbe_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop)
67 ixgbe_t *ixgbe = arg;
68 struct ixgbe_hw *hw = &ixgbe->hw;
69 boolean_t present, usable;
71 if (id != 0 || infop == NULL)
72 return (EINVAL);
74 mutex_enter(&ixgbe->gen_lock);
75 if (ixgbe_get_media_type(&ixgbe->hw) == ixgbe_media_type_copper) {
76 mutex_exit(&ixgbe->gen_lock);
77 return (ENOTSUP);
81 * Make sure we have the latest sfp information. This is especially
82 * important if the SFP is removed as that doesn't trigger interrupts in
83 * our current configuration.
85 (void) hw->phy.ops.identify_sfp(hw);
86 if (hw->phy.type == ixgbe_phy_none ||
87 (hw->phy.type == ixgbe_phy_unknown &&
88 hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
89 present = B_FALSE;
90 usable = B_FALSE;
91 } else {
92 present = B_TRUE;
93 usable = hw->phy.type != ixgbe_phy_sfp_unsupported;
96 mutex_exit(&ixgbe->gen_lock);
98 mac_transceiver_info_set_present(infop, present);
99 mac_transceiver_info_set_usable(infop, usable);
101 return (0);
105 * Note, we presume that the mac perimeter is held during these calls. As such,
106 * we rely on that for guaranteeing that only one thread is calling the i2c
107 * routines at any time.
110 ixgbe_transceiver_read(void *arg, uint_t id, uint_t page, void *bp,
111 size_t nbytes, off_t offset, size_t *nread)
113 ixgbe_t *ixgbe = arg;
114 struct ixgbe_hw *hw = &ixgbe->hw;
115 uint8_t *buf = bp;
116 size_t i;
117 boolean_t is8472;
119 if (id != 0 || buf == NULL || nbytes == 0 || nread == NULL ||
120 (page != 0xa0 && page != 0xa2) || offset < 0)
121 return (EINVAL);
124 * Both supported pages have a length of 256 bytes, ensure nothing asks
125 * us to go beyond that.
127 if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) {
128 return (EINVAL);
131 mutex_enter(&ixgbe->gen_lock);
132 if (ixgbe_get_media_type(&ixgbe->hw) == ixgbe_media_type_copper) {
133 mutex_exit(&ixgbe->gen_lock);
134 return (ENOTSUP);
137 if (hw->phy.ops.read_i2c_eeprom == NULL) {
138 mutex_exit(&ixgbe->gen_lock);
139 return (ENOTSUP);
142 if (ixgbe_transceiver_is_8472(ixgbe, &is8472) != 0) {
143 mutex_exit(&ixgbe->gen_lock);
144 return (EIO);
147 if (!is8472 && page == 0xa2) {
148 mutex_exit(&ixgbe->gen_lock);
149 return (EINVAL);
152 for (i = 0; i < nbytes; i++, offset++, buf++) {
153 int32_t ret;
155 if (page == 0xa0) {
156 ret = hw->phy.ops.read_i2c_eeprom(hw, offset, buf);
157 } else {
158 ret = hw->phy.ops.read_i2c_sff8472(hw, offset, buf);
160 if (ret != 0) {
161 mutex_exit(&ixgbe->gen_lock);
162 return (EIO);
165 mutex_exit(&ixgbe->gen_lock);
166 *nread = i;
168 return (0);