eeprom.c 6.9 KB

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