1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include <linux/ethtool.h>
4 #include <linux/sfp.h>
5 #include "netlink.h"
6 #include "common.h"
7
8 struct eeprom_req_info {
9 struct ethnl_req_info base;
10 u32 offset;
11 u32 length;
12 u8 page;
13 u8 bank;
14 u8 i2c_address;
15 };
16
17 struct eeprom_reply_data {
18 struct ethnl_reply_data base;
19 u32 length;
20 u8 *data;
21 };
22
23 #define MODULE_EEPROM_REQINFO(__req_base) \
24 container_of(__req_base, struct eeprom_req_info, base)
25
26 #define MODULE_EEPROM_REPDATA(__reply_base) \
27 container_of(__reply_base, struct eeprom_reply_data, base)
28
fallback_set_params(struct eeprom_req_info * request,struct ethtool_modinfo * modinfo,struct ethtool_eeprom * eeprom)29 static int fallback_set_params(struct eeprom_req_info *request,
30 struct ethtool_modinfo *modinfo,
31 struct ethtool_eeprom *eeprom)
32 {
33 u32 offset = request->offset;
34 u32 length = request->length;
35
36 if (request->page)
37 offset = request->page * ETH_MODULE_EEPROM_PAGE_LEN + offset;
38
39 if (modinfo->type == ETH_MODULE_SFF_8472 &&
40 request->i2c_address == 0x51)
41 offset += ETH_MODULE_EEPROM_PAGE_LEN * 2;
42
43 if (offset >= modinfo->eeprom_len)
44 return -EINVAL;
45
46 eeprom->cmd = ETHTOOL_GMODULEEEPROM;
47 eeprom->len = length;
48 eeprom->offset = offset;
49
50 return 0;
51 }
52
eeprom_fallback(struct eeprom_req_info * request,struct eeprom_reply_data * reply)53 static int eeprom_fallback(struct eeprom_req_info *request,
54 struct eeprom_reply_data *reply)
55 {
56 struct net_device *dev = reply->base.dev;
57 struct ethtool_modinfo modinfo = {0};
58 struct ethtool_eeprom eeprom = {0};
59 u8 *data;
60 int err;
61
62 modinfo.cmd = ETHTOOL_GMODULEINFO;
63 err = ethtool_get_module_info_call(dev, &modinfo);
64 if (err < 0)
65 return err;
66
67 err = fallback_set_params(request, &modinfo, &eeprom);
68 if (err < 0)
69 return err;
70
71 data = kmalloc(eeprom.len, GFP_KERNEL);
72 if (!data)
73 return -ENOMEM;
74 err = ethtool_get_module_eeprom_call(dev, &eeprom, data);
75 if (err < 0)
76 goto err_out;
77
78 reply->data = data;
79 reply->length = eeprom.len;
80
81 return 0;
82
83 err_out:
84 kfree(data);
85 return err;
86 }
87
get_module_eeprom_by_page(struct net_device * dev,struct ethtool_module_eeprom * page_data,struct netlink_ext_ack * extack)88 static int get_module_eeprom_by_page(struct net_device *dev,
89 struct ethtool_module_eeprom *page_data,
90 struct netlink_ext_ack *extack)
91 {
92 const struct ethtool_ops *ops = dev->ethtool_ops;
93
94 if (dev->ethtool->module_fw_flash_in_progress) {
95 NL_SET_ERR_MSG(extack,
96 "Module firmware flashing is in progress");
97 return -EBUSY;
98 }
99
100 if (dev->sfp_bus)
101 return sfp_get_module_eeprom_by_page(dev->sfp_bus, page_data, extack);
102
103 if (ops->get_module_eeprom_by_page)
104 return ops->get_module_eeprom_by_page(dev, page_data, extack);
105
106 return -EOPNOTSUPP;
107 }
108
eeprom_prepare_data(const struct ethnl_req_info * req_base,struct ethnl_reply_data * reply_base,const struct genl_info * info)109 static int eeprom_prepare_data(const struct ethnl_req_info *req_base,
110 struct ethnl_reply_data *reply_base,
111 const struct genl_info *info)
112 {
113 struct eeprom_reply_data *reply = MODULE_EEPROM_REPDATA(reply_base);
114 struct eeprom_req_info *request = MODULE_EEPROM_REQINFO(req_base);
115 struct ethtool_module_eeprom page_data = {0};
116 struct net_device *dev = reply_base->dev;
117 int ret;
118
119 page_data.offset = request->offset;
120 page_data.length = request->length;
121 page_data.i2c_address = request->i2c_address;
122 page_data.page = request->page;
123 page_data.bank = request->bank;
124 page_data.data = kmalloc(page_data.length, GFP_KERNEL);
125 if (!page_data.data)
126 return -ENOMEM;
127
128 ret = ethnl_ops_begin(dev);
129 if (ret)
130 goto err_free;
131
132 ret = get_module_eeprom_by_page(dev, &page_data, info->extack);
133 if (ret < 0)
134 goto err_ops;
135
136 reply->length = ret;
137 reply->data = page_data.data;
138
139 ethnl_ops_complete(dev);
140 return 0;
141
142 err_ops:
143 ethnl_ops_complete(dev);
144 err_free:
145 kfree(page_data.data);
146
147 if (ret == -EOPNOTSUPP)
148 return eeprom_fallback(request, reply);
149 return ret;
150 }
151
eeprom_parse_request(struct ethnl_req_info * req_info,struct nlattr ** tb,struct netlink_ext_ack * extack)152 static int eeprom_parse_request(struct ethnl_req_info *req_info, struct nlattr **tb,
153 struct netlink_ext_ack *extack)
154 {
155 struct eeprom_req_info *request = MODULE_EEPROM_REQINFO(req_info);
156
157 if (!tb[ETHTOOL_A_MODULE_EEPROM_OFFSET] ||
158 !tb[ETHTOOL_A_MODULE_EEPROM_LENGTH] ||
159 !tb[ETHTOOL_A_MODULE_EEPROM_PAGE] ||
160 !tb[ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS])
161 return -EINVAL;
162
163 request->i2c_address = nla_get_u8(tb[ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS]);
164 request->offset = nla_get_u32(tb[ETHTOOL_A_MODULE_EEPROM_OFFSET]);
165 request->length = nla_get_u32(tb[ETHTOOL_A_MODULE_EEPROM_LENGTH]);
166
167 /* The following set of conditions limit the API to only dump 1/2
168 * EEPROM page without crossing low page boundary located at offset 128.
169 * This means user may only request dumps of length limited to 128 from
170 * either low 128 bytes or high 128 bytes.
171 * For pages higher than 0 only high 128 bytes are accessible.
172 */
173 request->page = nla_get_u8(tb[ETHTOOL_A_MODULE_EEPROM_PAGE]);
174 if (request->page && request->offset < ETH_MODULE_EEPROM_PAGE_LEN) {
175 NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_MODULE_EEPROM_PAGE],
176 "reading from lower half page is allowed for page 0 only");
177 return -EINVAL;
178 }
179
180 if (request->offset < ETH_MODULE_EEPROM_PAGE_LEN &&
181 request->offset + request->length > ETH_MODULE_EEPROM_PAGE_LEN) {
182 NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_MODULE_EEPROM_LENGTH],
183 "reading cross half page boundary is illegal");
184 return -EINVAL;
185 } else if (request->offset + request->length > ETH_MODULE_EEPROM_PAGE_LEN * 2) {
186 NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_MODULE_EEPROM_LENGTH],
187 "reading cross page boundary is illegal");
188 return -EINVAL;
189 }
190
191 if (tb[ETHTOOL_A_MODULE_EEPROM_BANK])
192 request->bank = nla_get_u8(tb[ETHTOOL_A_MODULE_EEPROM_BANK]);
193
194 return 0;
195 }
196
eeprom_reply_size(const struct ethnl_req_info * req_base,const struct ethnl_reply_data * reply_base)197 static int eeprom_reply_size(const struct ethnl_req_info *req_base,
198 const struct ethnl_reply_data *reply_base)
199 {
200 const struct eeprom_req_info *request = MODULE_EEPROM_REQINFO(req_base);
201
202 return nla_total_size(sizeof(u8) * request->length); /* _EEPROM_DATA */
203 }
204
eeprom_fill_reply(struct sk_buff * skb,const struct ethnl_req_info * req_base,const struct ethnl_reply_data * reply_base)205 static int eeprom_fill_reply(struct sk_buff *skb,
206 const struct ethnl_req_info *req_base,
207 const struct ethnl_reply_data *reply_base)
208 {
209 struct eeprom_reply_data *reply = MODULE_EEPROM_REPDATA(reply_base);
210
211 return nla_put(skb, ETHTOOL_A_MODULE_EEPROM_DATA, reply->length, reply->data);
212 }
213
eeprom_cleanup_data(struct ethnl_reply_data * reply_base)214 static void eeprom_cleanup_data(struct ethnl_reply_data *reply_base)
215 {
216 struct eeprom_reply_data *reply = MODULE_EEPROM_REPDATA(reply_base);
217
218 kfree(reply->data);
219 }
220
221 const struct ethnl_request_ops ethnl_module_eeprom_request_ops = {
222 .request_cmd = ETHTOOL_MSG_MODULE_EEPROM_GET,
223 .reply_cmd = ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY,
224 .hdr_attr = ETHTOOL_A_MODULE_EEPROM_HEADER,
225 .req_info_size = sizeof(struct eeprom_req_info),
226 .reply_data_size = sizeof(struct eeprom_reply_data),
227
228 .parse_request = eeprom_parse_request,
229 .prepare_data = eeprom_prepare_data,
230 .reply_size = eeprom_reply_size,
231 .fill_reply = eeprom_fill_reply,
232 .cleanup_data = eeprom_cleanup_data,
233 };
234
235 const struct nla_policy ethnl_module_eeprom_get_policy[] = {
236 [ETHTOOL_A_MODULE_EEPROM_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
237 [ETHTOOL_A_MODULE_EEPROM_OFFSET] =
238 NLA_POLICY_MAX(NLA_U32, ETH_MODULE_EEPROM_PAGE_LEN * 2 - 1),
239 [ETHTOOL_A_MODULE_EEPROM_LENGTH] =
240 NLA_POLICY_RANGE(NLA_U32, 1, ETH_MODULE_EEPROM_PAGE_LEN),
241 [ETHTOOL_A_MODULE_EEPROM_PAGE] = { .type = NLA_U8 },
242 [ETHTOOL_A_MODULE_EEPROM_BANK] = { .type = NLA_U8 },
243 [ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS] =
244 NLA_POLICY_RANGE(NLA_U8, 0, ETH_MODULE_MAX_I2C_ADDRESS),
245 };
246
247