nfp_devlink.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
  3. #include <linux/rtnetlink.h>
  4. #include <net/devlink.h>
  5. #include "nfpcore/nfp.h"
  6. #include "nfpcore/nfp_nsp.h"
  7. #include "nfp_app.h"
  8. #include "nfp_main.h"
  9. #include "nfp_port.h"
  10. static int
  11. nfp_devlink_fill_eth_port(struct nfp_port *port,
  12. struct nfp_eth_table_port *copy)
  13. {
  14. struct nfp_eth_table_port *eth_port;
  15. eth_port = __nfp_port_get_eth_port(port);
  16. if (!eth_port)
  17. return -EINVAL;
  18. memcpy(copy, eth_port, sizeof(*eth_port));
  19. return 0;
  20. }
  21. static int
  22. nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf,
  23. struct devlink_port *dl_port,
  24. struct nfp_eth_table_port *copy)
  25. {
  26. struct nfp_port *port = container_of(dl_port, struct nfp_port, dl_port);
  27. return nfp_devlink_fill_eth_port(port, copy);
  28. }
  29. static int
  30. nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes)
  31. {
  32. struct nfp_nsp *nsp;
  33. int ret;
  34. nsp = nfp_eth_config_start(pf->cpp, idx);
  35. if (IS_ERR(nsp))
  36. return PTR_ERR(nsp);
  37. ret = __nfp_eth_set_split(nsp, lanes);
  38. if (ret) {
  39. nfp_eth_config_cleanup_end(nsp);
  40. return ret;
  41. }
  42. ret = nfp_eth_config_commit_end(nsp);
  43. if (ret < 0)
  44. return ret;
  45. if (ret) /* no change */
  46. return 0;
  47. return nfp_net_refresh_port_table_sync(pf);
  48. }
  49. static int
  50. nfp_devlink_port_split(struct devlink *devlink, struct devlink_port *port,
  51. unsigned int count, struct netlink_ext_ack *extack)
  52. {
  53. struct nfp_pf *pf = devlink_priv(devlink);
  54. struct nfp_eth_table_port eth_port;
  55. unsigned int lanes;
  56. int ret;
  57. rtnl_lock();
  58. ret = nfp_devlink_fill_eth_port_from_id(pf, port, &eth_port);
  59. rtnl_unlock();
  60. if (ret)
  61. return ret;
  62. if (eth_port.port_lanes % count) {
  63. NL_SET_ERR_MSG_MOD(extack, "invalid count");
  64. return -EINVAL;
  65. }
  66. /* Special case the 100G CXP -> 2x40G split */
  67. lanes = eth_port.port_lanes / count;
  68. if (eth_port.lanes == 10 && count == 2)
  69. lanes = 8 / count;
  70. return nfp_devlink_set_lanes(pf, eth_port.index, lanes);
  71. }
  72. static int
  73. nfp_devlink_port_unsplit(struct devlink *devlink, struct devlink_port *port,
  74. struct netlink_ext_ack *extack)
  75. {
  76. struct nfp_pf *pf = devlink_priv(devlink);
  77. struct nfp_eth_table_port eth_port;
  78. unsigned int lanes;
  79. int ret;
  80. rtnl_lock();
  81. ret = nfp_devlink_fill_eth_port_from_id(pf, port, &eth_port);
  82. rtnl_unlock();
  83. if (ret)
  84. return ret;
  85. if (!eth_port.is_split) {
  86. NL_SET_ERR_MSG_MOD(extack, "port is not split");
  87. return -EINVAL;
  88. }
  89. /* Special case the 100G CXP -> 2x40G unsplit */
  90. lanes = eth_port.port_lanes;
  91. if (eth_port.port_lanes == 8)
  92. lanes = 10;
  93. return nfp_devlink_set_lanes(pf, eth_port.index, lanes);
  94. }
  95. static int
  96. nfp_devlink_sb_pool_get(struct devlink *devlink, unsigned int sb_index,
  97. u16 pool_index, struct devlink_sb_pool_info *pool_info)
  98. {
  99. struct nfp_pf *pf = devlink_priv(devlink);
  100. return nfp_shared_buf_pool_get(pf, sb_index, pool_index, pool_info);
  101. }
  102. static int
  103. nfp_devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
  104. u16 pool_index,
  105. u32 size, enum devlink_sb_threshold_type threshold_type,
  106. struct netlink_ext_ack *extack)
  107. {
  108. struct nfp_pf *pf = devlink_priv(devlink);
  109. return nfp_shared_buf_pool_set(pf, sb_index, pool_index,
  110. size, threshold_type);
  111. }
  112. static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
  113. {
  114. struct nfp_pf *pf = devlink_priv(devlink);
  115. return nfp_app_eswitch_mode_get(pf->app, mode);
  116. }
  117. static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
  118. struct netlink_ext_ack *extack)
  119. {
  120. struct nfp_pf *pf = devlink_priv(devlink);
  121. return nfp_app_eswitch_mode_set(pf->app, mode);
  122. }
  123. static const struct nfp_devlink_versions_simple {
  124. const char *key;
  125. const char *hwinfo;
  126. } nfp_devlink_versions_hwinfo[] = {
  127. { DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, "assembly.partno", },
  128. { DEVLINK_INFO_VERSION_GENERIC_BOARD_REV, "assembly.revision", },
  129. { DEVLINK_INFO_VERSION_GENERIC_BOARD_MANUFACTURE, "assembly.vendor", },
  130. { "board.model", /* code name */ "assembly.model", },
  131. { DEVLINK_INFO_VERSION_GENERIC_BOARD_PART_NUMBER, "pn", },
  132. };
  133. static int
  134. nfp_devlink_versions_get_hwinfo(struct nfp_pf *pf, struct devlink_info_req *req)
  135. {
  136. unsigned int i;
  137. int err;
  138. for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_hwinfo); i++) {
  139. const struct nfp_devlink_versions_simple *info;
  140. const char *val;
  141. info = &nfp_devlink_versions_hwinfo[i];
  142. val = nfp_hwinfo_lookup(pf->hwinfo, info->hwinfo);
  143. if (!val)
  144. continue;
  145. err = devlink_info_version_fixed_put(req, info->key, val);
  146. if (err)
  147. return err;
  148. }
  149. return 0;
  150. }
  151. static const struct nfp_devlink_versions {
  152. enum nfp_nsp_versions id;
  153. const char *key;
  154. } nfp_devlink_versions_nsp[] = {
  155. { NFP_VERSIONS_BUNDLE, DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, },
  156. { NFP_VERSIONS_BSP, DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, },
  157. { NFP_VERSIONS_CPLD, "fw.cpld", },
  158. { NFP_VERSIONS_APP, DEVLINK_INFO_VERSION_GENERIC_FW_APP, },
  159. { NFP_VERSIONS_UNDI, DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, },
  160. { NFP_VERSIONS_NCSI, DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, },
  161. { NFP_VERSIONS_CFGR, "chip.init", },
  162. };
  163. static int
  164. nfp_devlink_versions_get_nsp(struct devlink_info_req *req, bool flash,
  165. const u8 *buf, unsigned int size)
  166. {
  167. unsigned int i;
  168. int err;
  169. for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_nsp); i++) {
  170. const struct nfp_devlink_versions *info;
  171. const char *version;
  172. info = &nfp_devlink_versions_nsp[i];
  173. version = nfp_nsp_versions_get(info->id, flash, buf, size);
  174. if (IS_ERR(version)) {
  175. if (PTR_ERR(version) == -ENOENT)
  176. continue;
  177. else
  178. return PTR_ERR(version);
  179. }
  180. if (flash)
  181. err = devlink_info_version_stored_put(req, info->key,
  182. version);
  183. else
  184. err = devlink_info_version_running_put(req, info->key,
  185. version);
  186. if (err)
  187. return err;
  188. }
  189. return 0;
  190. }
  191. static int
  192. nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
  193. struct netlink_ext_ack *extack)
  194. {
  195. struct nfp_pf *pf = devlink_priv(devlink);
  196. const char *sn, *vendor, *part;
  197. struct nfp_nsp *nsp;
  198. char *buf = NULL;
  199. int err;
  200. vendor = nfp_hwinfo_lookup(pf->hwinfo, "assembly.vendor");
  201. part = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno");
  202. sn = nfp_hwinfo_lookup(pf->hwinfo, "assembly.serial");
  203. if (vendor && part && sn) {
  204. char *buf;
  205. buf = kmalloc(strlen(vendor) + strlen(part) + strlen(sn) + 1,
  206. GFP_KERNEL);
  207. if (!buf)
  208. return -ENOMEM;
  209. buf[0] = '\0';
  210. strcat(buf, vendor);
  211. strcat(buf, part);
  212. strcat(buf, sn);
  213. err = devlink_info_serial_number_put(req, buf);
  214. kfree(buf);
  215. if (err)
  216. return err;
  217. }
  218. nsp = nfp_nsp_open(pf->cpp);
  219. if (IS_ERR(nsp)) {
  220. NL_SET_ERR_MSG_MOD(extack, "can't access NSP");
  221. return PTR_ERR(nsp);
  222. }
  223. if (nfp_nsp_has_versions(nsp)) {
  224. buf = kzalloc(NFP_NSP_VERSION_BUFSZ, GFP_KERNEL);
  225. if (!buf) {
  226. err = -ENOMEM;
  227. goto err_close_nsp;
  228. }
  229. err = nfp_nsp_versions(nsp, buf, NFP_NSP_VERSION_BUFSZ);
  230. if (err)
  231. goto err_free_buf;
  232. err = nfp_devlink_versions_get_nsp(req, false,
  233. buf, NFP_NSP_VERSION_BUFSZ);
  234. if (err)
  235. goto err_free_buf;
  236. err = nfp_devlink_versions_get_nsp(req, true,
  237. buf, NFP_NSP_VERSION_BUFSZ);
  238. if (err)
  239. goto err_free_buf;
  240. kfree(buf);
  241. }
  242. nfp_nsp_close(nsp);
  243. return nfp_devlink_versions_get_hwinfo(pf, req);
  244. err_free_buf:
  245. kfree(buf);
  246. err_close_nsp:
  247. nfp_nsp_close(nsp);
  248. return err;
  249. }
  250. static int
  251. nfp_devlink_flash_update(struct devlink *devlink,
  252. struct devlink_flash_update_params *params,
  253. struct netlink_ext_ack *extack)
  254. {
  255. return nfp_flash_update_common(devlink_priv(devlink), params->fw, extack);
  256. }
  257. const struct devlink_ops nfp_devlink_ops = {
  258. .sb_pool_get = nfp_devlink_sb_pool_get,
  259. .sb_pool_set = nfp_devlink_sb_pool_set,
  260. .eswitch_mode_get = nfp_devlink_eswitch_mode_get,
  261. .eswitch_mode_set = nfp_devlink_eswitch_mode_set,
  262. .info_get = nfp_devlink_info_get,
  263. .flash_update = nfp_devlink_flash_update,
  264. };
  265. static const struct devlink_port_ops nfp_devlink_port_ops = {
  266. .port_split = nfp_devlink_port_split,
  267. .port_unsplit = nfp_devlink_port_unsplit,
  268. };
  269. int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
  270. {
  271. struct devlink_port_attrs attrs = {};
  272. struct nfp_eth_table_port eth_port;
  273. struct devlink *devlink;
  274. const u8 *serial;
  275. int serial_len;
  276. int ret;
  277. SET_NETDEV_DEVLINK_PORT(port->netdev, &port->dl_port);
  278. rtnl_lock();
  279. ret = nfp_devlink_fill_eth_port(port, &eth_port);
  280. rtnl_unlock();
  281. if (ret)
  282. return ret;
  283. attrs.split = eth_port.is_split;
  284. attrs.splittable = eth_port.port_lanes > 1 && !attrs.split;
  285. attrs.lanes = eth_port.port_lanes;
  286. attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
  287. attrs.phys.port_number = eth_port.label_port;
  288. attrs.phys.split_subport_number = eth_port.label_subport;
  289. serial_len = nfp_cpp_serial(port->app->cpp, &serial);
  290. memcpy(attrs.switch_id.id, serial, serial_len);
  291. attrs.switch_id.id_len = serial_len;
  292. devlink_port_attrs_set(&port->dl_port, &attrs);
  293. devlink = priv_to_devlink(app->pf);
  294. return devl_port_register_with_ops(devlink, &port->dl_port,
  295. port->eth_id, &nfp_devlink_port_ops);
  296. }
  297. void nfp_devlink_port_unregister(struct nfp_port *port)
  298. {
  299. devl_port_unregister(&port->dl_port);
  300. }