1 // SPDX-License-Identifier: GPL-2.0-only
3 #include <linux/ethtool.h>
8 struct eeprom_req_info
{
9 struct ethnl_req_info base
;
17 struct eeprom_reply_data
{
18 struct ethnl_reply_data base
;
23 #define MODULE_EEPROM_REQINFO(__req_base) \
24 container_of(__req_base, struct eeprom_req_info, base)
26 #define MODULE_EEPROM_REPDATA(__reply_base) \
27 container_of(__reply_base, struct eeprom_reply_data, base)
29 static int fallback_set_params(struct eeprom_req_info
*request
,
30 struct ethtool_modinfo
*modinfo
,
31 struct ethtool_eeprom
*eeprom
)
33 u32 offset
= request
->offset
;
34 u32 length
= request
->length
;
37 offset
= request
->page
* ETH_MODULE_EEPROM_PAGE_LEN
+ offset
;
39 if (modinfo
->type
== ETH_MODULE_SFF_8472
&&
40 request
->i2c_address
== 0x51)
41 offset
+= ETH_MODULE_EEPROM_PAGE_LEN
* 2;
43 if (offset
>= modinfo
->eeprom_len
)
46 eeprom
->cmd
= ETHTOOL_GMODULEEEPROM
;
48 eeprom
->offset
= offset
;
53 static int eeprom_fallback(struct eeprom_req_info
*request
,
54 struct eeprom_reply_data
*reply
)
56 struct net_device
*dev
= reply
->base
.dev
;
57 struct ethtool_modinfo modinfo
= {0};
58 struct ethtool_eeprom eeprom
= {0};
62 modinfo
.cmd
= ETHTOOL_GMODULEINFO
;
63 err
= ethtool_get_module_info_call(dev
, &modinfo
);
67 err
= fallback_set_params(request
, &modinfo
, &eeprom
);
71 data
= kmalloc(eeprom
.len
, GFP_KERNEL
);
74 err
= ethtool_get_module_eeprom_call(dev
, &eeprom
, data
);
79 reply
->length
= eeprom
.len
;
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
)
92 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
94 if (dev
->ethtool
->module_fw_flash_in_progress
) {
95 NL_SET_ERR_MSG(extack
,
96 "Module firmware flashing is in progress");
101 return sfp_get_module_eeprom_by_page(dev
->sfp_bus
, page_data
, extack
);
103 if (ops
->get_module_eeprom_by_page
)
104 return ops
->get_module_eeprom_by_page(dev
, page_data
, extack
);
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
)
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
;
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
);
128 ret
= ethnl_ops_begin(dev
);
132 ret
= get_module_eeprom_by_page(dev
, &page_data
, info
->extack
);
137 reply
->data
= page_data
.data
;
139 ethnl_ops_complete(dev
);
143 ethnl_ops_complete(dev
);
145 kfree(page_data
.data
);
147 if (ret
== -EOPNOTSUPP
)
148 return eeprom_fallback(request
, reply
);
152 static int eeprom_parse_request(struct ethnl_req_info
*req_info
, struct nlattr
**tb
,
153 struct netlink_ext_ack
*extack
)
155 struct eeprom_req_info
*request
= MODULE_EEPROM_REQINFO(req_info
);
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
])
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
]);
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.
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");
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");
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");
191 if (tb
[ETHTOOL_A_MODULE_EEPROM_BANK
])
192 request
->bank
= nla_get_u8(tb
[ETHTOOL_A_MODULE_EEPROM_BANK
]);
197 static int eeprom_reply_size(const struct ethnl_req_info
*req_base
,
198 const struct ethnl_reply_data
*reply_base
)
200 const struct eeprom_req_info
*request
= MODULE_EEPROM_REQINFO(req_base
);
202 return nla_total_size(sizeof(u8
) * request
->length
); /* _EEPROM_DATA */
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
)
209 struct eeprom_reply_data
*reply
= MODULE_EEPROM_REPDATA(reply_base
);
211 return nla_put(skb
, ETHTOOL_A_MODULE_EEPROM_DATA
, reply
->length
, reply
->data
);
214 static void eeprom_cleanup_data(struct ethnl_reply_data
*reply_base
)
216 struct eeprom_reply_data
*reply
= MODULE_EEPROM_REPDATA(reply_base
);
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
),
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
,
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
),