Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/ethtool/eeprom.c
26278 views
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
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
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
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
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
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
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
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
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
248