diff options
author | Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> | 2018-03-20 10:58:09 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2018-03-26 13:24:54 -0400 |
commit | dc49c77236769c571e77d49450b2dfc001d60e33 (patch) | |
tree | 611bf76747dc07b17500965a6c1b5476d8f710ae /drivers/net/ethernet/intel/ice/ice_sched.c | |
parent | 9c20346b6309e20f64ee8e7054914ddc92c60baf (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.c | 328 |
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 | */ | ||
14 | static enum ice_status | ||
15 | ice_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 | */ | ||
55 | struct ice_sched_node * | ||
56 | ice_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 | */ | ||
96 | enum ice_status | ||
97 | ice_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 | */ | ||
343 | static enum ice_status | ||
344 | ice_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 | */ | ||
472 | static void | ||
473 | ice_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 | */ | ||
501 | static void | ||
502 | ice_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 | */ | ||
530 | enum 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 | |||
618 | err_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 | * |