eeprom.c 7.0 KB

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