aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/intel/ice/ice_sched.c
diff options
context:
space:
mode:
authorAnirudh Venkataramanan <anirudh.venkataramanan@intel.com>2018-03-20 10:58:09 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2018-03-26 13:24:54 -0400
commitdc49c77236769c571e77d49450b2dfc001d60e33 (patch)
tree611bf76747dc07b17500965a6c1b5476d8f710ae /drivers/net/ethernet/intel/ice/ice_sched.c
parent9c20346b6309e20f64ee8e7054914ddc92c60baf (diff)
ice: Get MAC/PHY/link info and scheduler topology
This patch adds code to continue the initialization flow as follows: 1) Get PHY/link information and store it 2) Get default scheduler tree topology and store it 3) Get the MAC address associated with the port and store it Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> Tested-by: Tony Brelinski <tonyx.brelinski@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_sched.c')
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sched.c328
1 files changed, 328 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
index ce4edf61ec8e..22039f9eb591 100644
--- a/drivers/net/ethernet/intel/ice/ice_sched.c
+++ b/drivers/net/ethernet/intel/ice/ice_sched.c
@@ -4,6 +4,141 @@
4#include "ice_sched.h" 4#include "ice_sched.h"
5 5
6/** 6/**
7 * ice_sched_add_root_node - Insert the Tx scheduler root node in SW DB
8 * @pi: port information structure
9 * @info: Scheduler element information from firmware
10 *
11 * This function inserts the root node of the scheduling tree topology
12 * to the SW DB.
13 */
14static enum ice_status
15ice_sched_add_root_node(struct ice_port_info *pi,
16 struct ice_aqc_txsched_elem_data *info)
17{
18 struct ice_sched_node *root;
19 struct ice_hw *hw;
20 u16 max_children;
21
22 if (!pi)
23 return ICE_ERR_PARAM;
24
25 hw = pi->hw;
26
27 root = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*root), GFP_KERNEL);
28 if (!root)
29 return ICE_ERR_NO_MEMORY;
30
31 max_children = le16_to_cpu(hw->layer_info[0].max_children);
32 root->children = devm_kcalloc(ice_hw_to_dev(hw), max_children,
33 sizeof(*root), GFP_KERNEL);
34 if (!root->children) {
35 devm_kfree(ice_hw_to_dev(hw), root);
36 return ICE_ERR_NO_MEMORY;
37 }
38
39 memcpy(&root->info, info, sizeof(*info));
40 pi->root = root;
41 return 0;
42}
43
44/**
45 * ice_sched_find_node_by_teid - Find the Tx scheduler node in SW DB
46 * @start_node: pointer to the starting ice_sched_node struct in a sub-tree
47 * @teid: node teid to search
48 *
49 * This function searches for a node matching the teid in the scheduling tree
50 * from the SW DB. The search is recursive and is restricted by the number of
51 * layers it has searched through; stopping at the max supported layer.
52 *
53 * This function needs to be called when holding the port_info->sched_lock
54 */
55struct ice_sched_node *
56ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid)
57{
58 u16 i;
59
60 /* The TEID is same as that of the start_node */
61 if (ICE_TXSCHED_GET_NODE_TEID(start_node) == teid)
62 return start_node;
63
64 /* The node has no children or is at the max layer */
65 if (!start_node->num_children ||
66 start_node->tx_sched_layer >= ICE_AQC_TOPO_MAX_LEVEL_NUM ||
67 start_node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF)
68 return NULL;
69
70 /* Check if teid matches to any of the children nodes */
71 for (i = 0; i < start_node->num_children; i++)
72 if (ICE_TXSCHED_GET_NODE_TEID(start_node->children[i]) == teid)
73 return start_node->children[i];
74
75 /* Search within each child's sub-tree */
76 for (i = 0; i < start_node->num_children; i++) {
77 struct ice_sched_node *tmp;
78
79 tmp = ice_sched_find_node_by_teid(start_node->children[i],
80 teid);
81 if (tmp)
82 return tmp;
83 }
84
85 return NULL;
86}
87
88/**
89 * ice_sched_add_node - Insert the Tx scheduler node in SW DB
90 * @pi: port information structure
91 * @layer: Scheduler layer of the node
92 * @info: Scheduler element information from firmware
93 *
94 * This function inserts a scheduler node to the SW DB.
95 */
96enum ice_status
97ice_sched_add_node(struct ice_port_info *pi, u8 layer,
98 struct ice_aqc_txsched_elem_data *info)
99{
100 struct ice_sched_node *parent;
101 struct ice_sched_node *node;
102 struct ice_hw *hw;
103 u16 max_children;
104
105 if (!pi)
106 return ICE_ERR_PARAM;
107
108 hw = pi->hw;
109
110 /* A valid parent node should be there */
111 parent = ice_sched_find_node_by_teid(pi->root,
112 le32_to_cpu(info->parent_teid));
113 if (!parent) {
114 ice_debug(hw, ICE_DBG_SCHED,
115 "Parent Node not found for parent_teid=0x%x\n",
116 le32_to_cpu(info->parent_teid));
117 return ICE_ERR_PARAM;
118 }
119
120 node = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*node), GFP_KERNEL);
121 if (!node)
122 return ICE_ERR_NO_MEMORY;
123 max_children = le16_to_cpu(hw->layer_info[layer].max_children);
124 if (max_children) {
125 node->children = devm_kcalloc(ice_hw_to_dev(hw), max_children,
126 sizeof(*node), GFP_KERNEL);
127 if (!node->children) {
128 devm_kfree(ice_hw_to_dev(hw), node);
129 return ICE_ERR_NO_MEMORY;
130 }
131 }
132
133 node->in_use = true;
134 node->parent = parent;
135 node->tx_sched_layer = layer;
136 parent->children[parent->num_children++] = node;
137 memcpy(&node->info, info, sizeof(*info));
138 return 0;
139}
140
141/**
7 * ice_aq_delete_sched_elems - delete scheduler elements 142 * ice_aq_delete_sched_elems - delete scheduler elements
8 * @hw: pointer to the hw struct 143 * @hw: pointer to the hw struct
9 * @grps_req: number of groups to delete 144 * @grps_req: number of groups to delete
@@ -195,6 +330,36 @@ err_exit:
195} 330}
196 331
197/** 332/**
333 * ice_aq_get_dflt_topo - gets default scheduler topology
334 * @hw: pointer to the hw struct
335 * @lport: logical port number
336 * @buf: pointer to buffer
337 * @buf_size: buffer size in bytes
338 * @num_branches: returns total number of queue to port branches
339 * @cd: pointer to command details structure or NULL
340 *
341 * Get default scheduler topology (0x400)
342 */
343static enum ice_status
344ice_aq_get_dflt_topo(struct ice_hw *hw, u8 lport,
345 struct ice_aqc_get_topo_elem *buf, u16 buf_size,
346 u8 *num_branches, struct ice_sq_cd *cd)
347{
348 struct ice_aqc_get_topo *cmd;
349 struct ice_aq_desc desc;
350 enum ice_status status;
351
352 cmd = &desc.params.get_topo;
353 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_dflt_topo);
354 cmd->port_num = lport;
355 status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
356 if (!status && num_branches)
357 *num_branches = cmd->num_branches;
358
359 return status;
360}
361
362/**
198 * ice_aq_query_sched_res - query scheduler resource 363 * ice_aq_query_sched_res - query scheduler resource
199 * @hw: pointer to the hw struct 364 * @hw: pointer to the hw struct
200 * @buf_size: buffer size in bytes 365 * @buf_size: buffer size in bytes
@@ -298,6 +463,169 @@ void ice_sched_cleanup_all(struct ice_hw *hw)
298} 463}
299 464
300/** 465/**
466 * ice_rm_dflt_leaf_node - remove the default leaf node in the tree
467 * @pi: port information structure
468 *
469 * This function removes the leaf node that was created by the FW
470 * during initialization
471 */
472static void
473ice_rm_dflt_leaf_node(struct ice_port_info *pi)
474{
475 struct ice_sched_node *node;
476
477 node = pi->root;
478 while (node) {
479 if (!node->num_children)
480 break;
481 node = node->children[0];
482 }
483 if (node && node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF) {
484 u32 teid = le32_to_cpu(node->info.node_teid);
485 enum ice_status status;
486
487 /* remove the default leaf node */
488 status = ice_sched_remove_elems(pi->hw, node->parent, 1, &teid);
489 if (!status)
490 ice_free_sched_node(pi, node);
491 }
492}
493
494/**
495 * ice_sched_rm_dflt_nodes - free the default nodes in the tree
496 * @pi: port information structure
497 *
498 * This function frees all the nodes except root and TC that were created by
499 * the FW during initialization
500 */
501static void
502ice_sched_rm_dflt_nodes(struct ice_port_info *pi)
503{
504 struct ice_sched_node *node;
505
506 ice_rm_dflt_leaf_node(pi);
507 /* remove the default nodes except TC and root nodes */
508 node = pi->root;
509 while (node) {
510 if (node->tx_sched_layer >= pi->hw->sw_entry_point_layer &&
511 node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC &&
512 node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT) {
513 ice_free_sched_node(pi, node);
514 break;
515 }
516 if (!node->num_children)
517 break;
518 node = node->children[0];
519 }
520}
521
522/**
523 * ice_sched_init_port - Initialize scheduler by querying information from FW
524 * @pi: port info structure for the tree to cleanup
525 *
526 * This function is the initial call to find the total number of Tx scheduler
527 * resources, default topology created by firmware and storing the information
528 * in SW DB.
529 */
530enum ice_status ice_sched_init_port(struct ice_port_info *pi)
531{
532 struct ice_aqc_get_topo_elem *buf;
533 enum ice_status status;
534 struct ice_hw *hw;
535 u8 num_branches;
536 u16 num_elems;
537 u8 i, j;
538
539 if (!pi)
540 return ICE_ERR_PARAM;
541 hw = pi->hw;
542
543 /* Query the Default Topology from FW */
544 buf = devm_kcalloc(ice_hw_to_dev(hw), ICE_TXSCHED_MAX_BRANCHES,
545 sizeof(*buf), GFP_KERNEL);
546 if (!buf)
547 return ICE_ERR_NO_MEMORY;
548
549 /* Query default scheduling tree topology */
550 status = ice_aq_get_dflt_topo(hw, pi->lport, buf,
551 sizeof(*buf) * ICE_TXSCHED_MAX_BRANCHES,
552 &num_branches, NULL);
553 if (status)
554 goto err_init_port;
555
556 /* num_branches should be between 1-8 */
557 if (num_branches < 1 || num_branches > ICE_TXSCHED_MAX_BRANCHES) {
558 ice_debug(hw, ICE_DBG_SCHED, "num_branches unexpected %d\n",
559 num_branches);
560 status = ICE_ERR_PARAM;
561 goto err_init_port;
562 }
563
564 /* get the number of elements on the default/first branch */
565 num_elems = le16_to_cpu(buf[0].hdr.num_elems);
566
567 /* num_elems should always be between 1-9 */
568 if (num_elems < 1 || num_elems > ICE_AQC_TOPO_MAX_LEVEL_NUM) {
569 ice_debug(hw, ICE_DBG_SCHED, "num_elems unexpected %d\n",
570 num_elems);
571 status = ICE_ERR_PARAM;
572 goto err_init_port;
573 }
574
575 /* If the last node is a leaf node then the index of the Q group
576 * layer is two less than the number of elements.
577 */
578 if (num_elems > 2 && buf[0].generic[num_elems - 1].data.elem_type ==
579 ICE_AQC_ELEM_TYPE_LEAF)
580 pi->last_node_teid =
581 le32_to_cpu(buf[0].generic[num_elems - 2].node_teid);
582 else
583 pi->last_node_teid =
584 le32_to_cpu(buf[0].generic[num_elems - 1].node_teid);
585
586 /* Insert the Tx Sched root node */
587 status = ice_sched_add_root_node(pi, &buf[0].generic[0]);
588 if (status)
589 goto err_init_port;
590
591 /* Parse the default tree and cache the information */
592 for (i = 0; i < num_branches; i++) {
593 num_elems = le16_to_cpu(buf[i].hdr.num_elems);
594
595 /* Skip root element as already inserted */
596 for (j = 1; j < num_elems; j++) {
597 /* update the sw entry point */
598 if (buf[0].generic[j].data.elem_type ==
599 ICE_AQC_ELEM_TYPE_ENTRY_POINT)
600 hw->sw_entry_point_layer = j;
601
602 status = ice_sched_add_node(pi, j, &buf[i].generic[j]);
603 if (status)
604 goto err_init_port;
605 }
606 }
607
608 /* Remove the default nodes. */
609 if (pi->root)
610 ice_sched_rm_dflt_nodes(pi);
611
612 /* initialize the port for handling the scheduler tree */
613 pi->port_state = ICE_SCHED_PORT_STATE_READY;
614 mutex_init(&pi->sched_lock);
615 INIT_LIST_HEAD(&pi->agg_list);
616 INIT_LIST_HEAD(&pi->vsi_info_list);
617
618err_init_port:
619 if (status && pi->root) {
620 ice_free_sched_node(pi, pi->root);
621 pi->root = NULL;
622 }
623
624 devm_kfree(ice_hw_to_dev(hw), buf);
625 return status;
626}
627
628/**
301 * ice_sched_query_res_alloc - query the FW for num of logical sched layers 629 * ice_sched_query_res_alloc - query the FW for num of logical sched layers
302 * @hw: pointer to the HW struct 630 * @hw: pointer to the HW struct
303 * 631 *