ws.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2. /* Copyright (c) 2017 - 2021 Intel Corporation */
  3. #include "osdep.h"
  4. #include "hmc.h"
  5. #include "defs.h"
  6. #include "type.h"
  7. #include "protos.h"
  8. #include "ws.h"
  9. /**
  10. * irdma_alloc_node - Allocate a WS node and init
  11. * @vsi: vsi pointer
  12. * @user_pri: user priority
  13. * @node_type: Type of node, leaf or parent
  14. * @parent: parent node pointer
  15. */
  16. static struct irdma_ws_node *irdma_alloc_node(struct irdma_sc_vsi *vsi,
  17. u8 user_pri,
  18. enum irdma_ws_node_type node_type,
  19. struct irdma_ws_node *parent)
  20. {
  21. struct irdma_virt_mem ws_mem;
  22. struct irdma_ws_node *node;
  23. u16 node_index = 0;
  24. ws_mem.size = sizeof(struct irdma_ws_node);
  25. ws_mem.va = kzalloc(ws_mem.size, GFP_KERNEL);
  26. if (!ws_mem.va)
  27. return NULL;
  28. if (parent) {
  29. node_index = irdma_alloc_ws_node_id(vsi->dev);
  30. if (node_index == IRDMA_WS_NODE_INVALID) {
  31. kfree(ws_mem.va);
  32. return NULL;
  33. }
  34. }
  35. node = ws_mem.va;
  36. node->index = node_index;
  37. node->vsi_index = vsi->vsi_idx;
  38. INIT_LIST_HEAD(&node->child_list_head);
  39. if (node_type == WS_NODE_TYPE_LEAF) {
  40. node->type_leaf = true;
  41. node->traffic_class = vsi->qos[user_pri].traffic_class;
  42. node->user_pri = user_pri;
  43. node->rel_bw = vsi->qos[user_pri].rel_bw;
  44. if (!node->rel_bw)
  45. node->rel_bw = 1;
  46. node->lan_qs_handle = vsi->qos[user_pri].lan_qos_handle;
  47. node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
  48. } else {
  49. node->rel_bw = 1;
  50. node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
  51. node->enable = true;
  52. }
  53. node->parent = parent;
  54. return node;
  55. }
  56. /**
  57. * irdma_free_node - Free a WS node
  58. * @vsi: VSI stricture of device
  59. * @node: Pointer to node to free
  60. */
  61. static void irdma_free_node(struct irdma_sc_vsi *vsi,
  62. struct irdma_ws_node *node)
  63. {
  64. struct irdma_virt_mem ws_mem;
  65. if (node->index)
  66. irdma_free_ws_node_id(vsi->dev, node->index);
  67. ws_mem.va = node;
  68. ws_mem.size = sizeof(struct irdma_ws_node);
  69. kfree(ws_mem.va);
  70. }
  71. /**
  72. * irdma_ws_cqp_cmd - Post CQP work scheduler node cmd
  73. * @vsi: vsi pointer
  74. * @node: pointer to node
  75. * @cmd: add, remove or modify
  76. */
  77. static int irdma_ws_cqp_cmd(struct irdma_sc_vsi *vsi,
  78. struct irdma_ws_node *node, u8 cmd)
  79. {
  80. struct irdma_ws_node_info node_info = {};
  81. node_info.id = node->index;
  82. node_info.vsi = node->vsi_index;
  83. if (node->parent)
  84. node_info.parent_id = node->parent->index;
  85. else
  86. node_info.parent_id = node_info.id;
  87. node_info.weight = node->rel_bw;
  88. node_info.tc = node->traffic_class;
  89. node_info.prio_type = node->prio_type;
  90. node_info.type_leaf = node->type_leaf;
  91. node_info.enable = node->enable;
  92. if (irdma_cqp_ws_node_cmd(vsi->dev, cmd, &node_info)) {
  93. ibdev_dbg(to_ibdev(vsi->dev), "WS: CQP WS CMD failed\n");
  94. return -ENOMEM;
  95. }
  96. if (node->type_leaf && cmd == IRDMA_OP_WS_ADD_NODE) {
  97. node->qs_handle = node_info.qs_handle;
  98. vsi->qos[node->user_pri].qs_handle = node_info.qs_handle;
  99. }
  100. return 0;
  101. }
  102. /**
  103. * ws_find_node - Find SC WS node based on VSI id or TC
  104. * @parent: parent node of First VSI or TC node
  105. * @match_val: value to match
  106. * @type: match type VSI/TC
  107. */
  108. static struct irdma_ws_node *ws_find_node(struct irdma_ws_node *parent,
  109. u16 match_val,
  110. enum irdma_ws_match_type type)
  111. {
  112. struct irdma_ws_node *node;
  113. switch (type) {
  114. case WS_MATCH_TYPE_VSI:
  115. list_for_each_entry(node, &parent->child_list_head, siblings) {
  116. if (node->vsi_index == match_val)
  117. return node;
  118. }
  119. break;
  120. case WS_MATCH_TYPE_TC:
  121. list_for_each_entry(node, &parent->child_list_head, siblings) {
  122. if (node->traffic_class == match_val)
  123. return node;
  124. }
  125. break;
  126. default:
  127. break;
  128. }
  129. return NULL;
  130. }
  131. /**
  132. * irdma_tc_in_use - Checks to see if a leaf node is in use
  133. * @vsi: vsi pointer
  134. * @user_pri: user priority
  135. */
  136. static bool irdma_tc_in_use(struct irdma_sc_vsi *vsi, u8 user_pri)
  137. {
  138. int i;
  139. mutex_lock(&vsi->qos[user_pri].qos_mutex);
  140. if (!list_empty(&vsi->qos[user_pri].qplist)) {
  141. mutex_unlock(&vsi->qos[user_pri].qos_mutex);
  142. return true;
  143. }
  144. /* Check if the traffic class associated with the given user priority
  145. * is in use by any other user priority. If so, nothing left to do
  146. */
  147. for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
  148. if (vsi->qos[i].traffic_class == vsi->qos[user_pri].traffic_class &&
  149. !list_empty(&vsi->qos[i].qplist)) {
  150. mutex_unlock(&vsi->qos[user_pri].qos_mutex);
  151. return true;
  152. }
  153. }
  154. mutex_unlock(&vsi->qos[user_pri].qos_mutex);
  155. return false;
  156. }
  157. /**
  158. * irdma_remove_leaf - Remove leaf node unconditionally
  159. * @vsi: vsi pointer
  160. * @user_pri: user priority
  161. */
  162. static void irdma_remove_leaf(struct irdma_sc_vsi *vsi, u8 user_pri)
  163. {
  164. struct irdma_ws_node *ws_tree_root, *vsi_node, *tc_node;
  165. int i;
  166. u16 traffic_class;
  167. traffic_class = vsi->qos[user_pri].traffic_class;
  168. for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++)
  169. if (vsi->qos[i].traffic_class == traffic_class)
  170. vsi->qos[i].valid = false;
  171. ws_tree_root = vsi->dev->ws_tree_root;
  172. if (!ws_tree_root)
  173. return;
  174. vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
  175. WS_MATCH_TYPE_VSI);
  176. if (!vsi_node)
  177. return;
  178. tc_node = ws_find_node(vsi_node,
  179. vsi->qos[user_pri].traffic_class,
  180. WS_MATCH_TYPE_TC);
  181. if (!tc_node)
  182. return;
  183. irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
  184. vsi->unregister_qset(vsi, tc_node);
  185. list_del(&tc_node->siblings);
  186. irdma_free_node(vsi, tc_node);
  187. /* Check if VSI node can be freed */
  188. if (list_empty(&vsi_node->child_list_head)) {
  189. irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE);
  190. list_del(&vsi_node->siblings);
  191. irdma_free_node(vsi, vsi_node);
  192. /* Free head node there are no remaining VSI nodes */
  193. if (list_empty(&ws_tree_root->child_list_head)) {
  194. irdma_ws_cqp_cmd(vsi, ws_tree_root,
  195. IRDMA_OP_WS_DELETE_NODE);
  196. irdma_free_node(vsi, ws_tree_root);
  197. vsi->dev->ws_tree_root = NULL;
  198. }
  199. }
  200. }
  201. /**
  202. * irdma_ws_add - Build work scheduler tree, set RDMA qs_handle
  203. * @vsi: vsi pointer
  204. * @user_pri: user priority
  205. */
  206. int irdma_ws_add(struct irdma_sc_vsi *vsi, u8 user_pri)
  207. {
  208. struct irdma_ws_node *ws_tree_root;
  209. struct irdma_ws_node *vsi_node;
  210. struct irdma_ws_node *tc_node;
  211. u16 traffic_class;
  212. int ret = 0;
  213. int i;
  214. mutex_lock(&vsi->dev->ws_mutex);
  215. if (vsi->tc_change_pending) {
  216. ret = -EBUSY;
  217. goto exit;
  218. }
  219. if (vsi->qos[user_pri].valid)
  220. goto exit;
  221. ws_tree_root = vsi->dev->ws_tree_root;
  222. if (!ws_tree_root) {
  223. ibdev_dbg(to_ibdev(vsi->dev), "WS: Creating root node\n");
  224. ws_tree_root = irdma_alloc_node(vsi, user_pri,
  225. WS_NODE_TYPE_PARENT, NULL);
  226. if (!ws_tree_root) {
  227. ret = -ENOMEM;
  228. goto exit;
  229. }
  230. ret = irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_ADD_NODE);
  231. if (ret) {
  232. irdma_free_node(vsi, ws_tree_root);
  233. goto exit;
  234. }
  235. vsi->dev->ws_tree_root = ws_tree_root;
  236. }
  237. /* Find a second tier node that matches the VSI */
  238. vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
  239. WS_MATCH_TYPE_VSI);
  240. /* If VSI node doesn't exist, add one */
  241. if (!vsi_node) {
  242. ibdev_dbg(to_ibdev(vsi->dev),
  243. "WS: Node not found matching VSI %d\n",
  244. vsi->vsi_idx);
  245. vsi_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_PARENT,
  246. ws_tree_root);
  247. if (!vsi_node) {
  248. ret = -ENOMEM;
  249. goto vsi_add_err;
  250. }
  251. ret = irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_ADD_NODE);
  252. if (ret) {
  253. irdma_free_node(vsi, vsi_node);
  254. goto vsi_add_err;
  255. }
  256. list_add(&vsi_node->siblings, &ws_tree_root->child_list_head);
  257. }
  258. ibdev_dbg(to_ibdev(vsi->dev),
  259. "WS: Using node %d which represents VSI %d\n",
  260. vsi_node->index, vsi->vsi_idx);
  261. traffic_class = vsi->qos[user_pri].traffic_class;
  262. tc_node = ws_find_node(vsi_node, traffic_class,
  263. WS_MATCH_TYPE_TC);
  264. if (!tc_node) {
  265. /* Add leaf node */
  266. ibdev_dbg(to_ibdev(vsi->dev),
  267. "WS: Node not found matching VSI %d and TC %d\n",
  268. vsi->vsi_idx, traffic_class);
  269. tc_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_LEAF,
  270. vsi_node);
  271. if (!tc_node) {
  272. ret = -ENOMEM;
  273. goto leaf_add_err;
  274. }
  275. ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_ADD_NODE);
  276. if (ret) {
  277. irdma_free_node(vsi, tc_node);
  278. goto leaf_add_err;
  279. }
  280. list_add(&tc_node->siblings, &vsi_node->child_list_head);
  281. /*
  282. * callback to LAN to update the LAN tree with our node
  283. */
  284. ret = vsi->register_qset(vsi, tc_node);
  285. if (ret)
  286. goto reg_err;
  287. tc_node->enable = true;
  288. ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_MODIFY_NODE);
  289. if (ret) {
  290. vsi->unregister_qset(vsi, tc_node);
  291. goto reg_err;
  292. }
  293. }
  294. ibdev_dbg(to_ibdev(vsi->dev),
  295. "WS: Using node %d which represents VSI %d TC %d\n",
  296. tc_node->index, vsi->vsi_idx, traffic_class);
  297. /*
  298. * Iterate through other UPs and update the QS handle if they have
  299. * a matching traffic class.
  300. */
  301. for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
  302. if (vsi->qos[i].traffic_class == traffic_class) {
  303. vsi->qos[i].qs_handle = tc_node->qs_handle;
  304. vsi->qos[i].lan_qos_handle = tc_node->lan_qs_handle;
  305. vsi->qos[i].l2_sched_node_id = tc_node->l2_sched_node_id;
  306. vsi->qos[i].valid = true;
  307. }
  308. }
  309. goto exit;
  310. reg_err:
  311. irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
  312. list_del(&tc_node->siblings);
  313. irdma_free_node(vsi, tc_node);
  314. leaf_add_err:
  315. if (list_empty(&vsi_node->child_list_head)) {
  316. if (irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE))
  317. goto exit;
  318. list_del(&vsi_node->siblings);
  319. irdma_free_node(vsi, vsi_node);
  320. }
  321. vsi_add_err:
  322. /* Free head node there are no remaining VSI nodes */
  323. if (list_empty(&ws_tree_root->child_list_head)) {
  324. irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_DELETE_NODE);
  325. vsi->dev->ws_tree_root = NULL;
  326. irdma_free_node(vsi, ws_tree_root);
  327. }
  328. exit:
  329. mutex_unlock(&vsi->dev->ws_mutex);
  330. return ret;
  331. }
  332. /**
  333. * irdma_ws_remove - Free WS scheduler node, update WS tree
  334. * @vsi: vsi pointer
  335. * @user_pri: user priority
  336. */
  337. void irdma_ws_remove(struct irdma_sc_vsi *vsi, u8 user_pri)
  338. {
  339. mutex_lock(&vsi->dev->ws_mutex);
  340. if (irdma_tc_in_use(vsi, user_pri))
  341. goto exit;
  342. irdma_remove_leaf(vsi, user_pri);
  343. exit:
  344. mutex_unlock(&vsi->dev->ws_mutex);
  345. }
  346. /**
  347. * irdma_ws_reset - Reset entire WS tree
  348. * @vsi: vsi pointer
  349. */
  350. void irdma_ws_reset(struct irdma_sc_vsi *vsi)
  351. {
  352. u8 i;
  353. mutex_lock(&vsi->dev->ws_mutex);
  354. for (i = 0; i < IRDMA_MAX_USER_PRIORITY; ++i)
  355. irdma_remove_leaf(vsi, i);
  356. mutex_unlock(&vsi->dev->ws_mutex);
  357. }