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:08 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2018-03-26 13:14:57 -0400
commit9c20346b6309e20f64ee8e7054914ddc92c60baf (patch)
treeefc92292f19570987f9bb4e9c0be518efa98efe6 /drivers/net/ethernet/intel/ice/ice_sched.c
parentf31e4b6fe227dfd7ed51c3fc0550878c7d7a8cf2 (diff)
ice: Get switch config, scheduler config and device capabilities
This patch adds to the initialization flow by getting switch configuration, scheduler configuration and device capabilities. Switch configuration: On boot, an L2 switch element is created in the firmware per physical function. Each physical function is also mapped to a port, to which its switch element is connected. In other words, this switch can be visualized as an embedded vSwitch that can connect a physical function's virtual station interfaces (VSIs) to the egress/ingress port. Egress/ingress filters will be eventually created and applied on this switch element. As part of the initialization flow, the driver gets configuration data from this switch element and stores it. Scheduler configuration: The Tx scheduler is a subsystem responsible for setting and enforcing QoS. As part of the initialization flow, the driver queries and stores the default scheduler configuration for the given physical function. Device capabilities: As part of initialization, the driver has to determine what the device is capable of (ex. max queues, VSIs, etc). This information is obtained from the firmware and stored by the driver. CC: Shannon Nelson <shannon.nelson@oracle.com> Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> Acked-by: Shannon Nelson <shannon.nelson@oracle.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.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
new file mode 100644
index 000000000000..ce4edf61ec8e
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_sched.c
@@ -0,0 +1,340 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2018, Intel Corporation. */
3
4#include "ice_sched.h"
5
6/**
7 * ice_aq_delete_sched_elems - delete scheduler elements
8 * @hw: pointer to the hw struct
9 * @grps_req: number of groups to delete
10 * @buf: pointer to buffer
11 * @buf_size: buffer size in bytes
12 * @grps_del: returns total number of elements deleted
13 * @cd: pointer to command details structure or NULL
14 *
15 * Delete scheduling elements (0x040F)
16 */
17static enum ice_status
18ice_aq_delete_sched_elems(struct ice_hw *hw, u16 grps_req,
19 struct ice_aqc_delete_elem *buf, u16 buf_size,
20 u16 *grps_del, struct ice_sq_cd *cd)
21{
22 struct ice_aqc_add_move_delete_elem *cmd;
23 struct ice_aq_desc desc;
24 enum ice_status status;
25
26 cmd = &desc.params.add_move_delete_elem;
27 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_delete_sched_elems);
28 desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
29 cmd->num_grps_req = cpu_to_le16(grps_req);
30
31 status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
32 if (!status && grps_del)
33 *grps_del = le16_to_cpu(cmd->num_grps_updated);
34
35 return status;
36}
37
38/**
39 * ice_sched_remove_elems - remove nodes from hw
40 * @hw: pointer to the hw struct
41 * @parent: pointer to the parent node
42 * @num_nodes: number of nodes
43 * @node_teids: array of node teids to be deleted
44 *
45 * This function remove nodes from hw
46 */
47static enum ice_status
48ice_sched_remove_elems(struct ice_hw *hw, struct ice_sched_node *parent,
49 u16 num_nodes, u32 *node_teids)
50{
51 struct ice_aqc_delete_elem *buf;
52 u16 i, num_groups_removed = 0;
53 enum ice_status status;
54 u16 buf_size;
55
56 buf_size = sizeof(*buf) + sizeof(u32) * (num_nodes - 1);
57 buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL);
58 if (!buf)
59 return ICE_ERR_NO_MEMORY;
60 buf->hdr.parent_teid = parent->info.node_teid;
61 buf->hdr.num_elems = cpu_to_le16(num_nodes);
62 for (i = 0; i < num_nodes; i++)
63 buf->teid[i] = cpu_to_le32(node_teids[i]);
64 status = ice_aq_delete_sched_elems(hw, 1, buf, buf_size,
65 &num_groups_removed, NULL);
66 if (status || num_groups_removed != 1)
67 ice_debug(hw, ICE_DBG_SCHED, "remove elements failed\n");
68 devm_kfree(ice_hw_to_dev(hw), buf);
69 return status;
70}
71
72/**
73 * ice_sched_get_first_node - get the first node of the given layer
74 * @hw: pointer to the hw struct
75 * @parent: pointer the base node of the subtree
76 * @layer: layer number
77 *
78 * This function retrieves the first node of the given layer from the subtree
79 */
80static struct ice_sched_node *
81ice_sched_get_first_node(struct ice_hw *hw, struct ice_sched_node *parent,
82 u8 layer)
83{
84 u8 i;
85
86 if (layer < hw->sw_entry_point_layer)
87 return NULL;
88 for (i = 0; i < parent->num_children; i++) {
89 struct ice_sched_node *node = parent->children[i];
90
91 if (node) {
92 if (node->tx_sched_layer == layer)
93 return node;
94 /* this recursion is intentional, and wouldn't
95 * go more than 9 calls
96 */
97 return ice_sched_get_first_node(hw, node, layer);
98 }
99 }
100 return NULL;
101}
102
103/**
104 * ice_sched_get_tc_node - get pointer to TC node
105 * @pi: port information structure
106 * @tc: TC number
107 *
108 * This function returns the TC node pointer
109 */
110struct ice_sched_node *ice_sched_get_tc_node(struct ice_port_info *pi, u8 tc)
111{
112 u8 i;
113
114 if (!pi)
115 return NULL;
116 for (i = 0; i < pi->root->num_children; i++)
117 if (pi->root->children[i]->tc_num == tc)
118 return pi->root->children[i];
119 return NULL;
120}
121
122/**
123 * ice_free_sched_node - Free a Tx scheduler node from SW DB
124 * @pi: port information structure
125 * @node: pointer to the ice_sched_node struct
126 *
127 * This function frees up a node from SW DB as well as from HW
128 *
129 * This function needs to be called with the port_info->sched_lock held
130 */
131void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node)
132{
133 struct ice_sched_node *parent;
134 struct ice_hw *hw = pi->hw;
135 u8 i, j;
136
137 /* Free the children before freeing up the parent node
138 * The parent array is updated below and that shifts the nodes
139 * in the array. So always pick the first child if num children > 0
140 */
141 while (node->num_children)
142 ice_free_sched_node(pi, node->children[0]);
143
144 /* Leaf, TC and root nodes can't be deleted by SW */
145 if (node->tx_sched_layer >= hw->sw_entry_point_layer &&
146 node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC &&
147 node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT &&
148 node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF) {
149 u32 teid = le32_to_cpu(node->info.node_teid);
150 enum ice_status status;
151
152 status = ice_sched_remove_elems(hw, node->parent, 1, &teid);
153 if (status)
154 ice_debug(hw, ICE_DBG_SCHED,
155 "remove element failed %d\n", status);
156 }
157 parent = node->parent;
158 /* root has no parent */
159 if (parent) {
160 struct ice_sched_node *p, *tc_node;
161
162 /* update the parent */
163 for (i = 0; i < parent->num_children; i++)
164 if (parent->children[i] == node) {
165 for (j = i + 1; j < parent->num_children; j++)
166 parent->children[j - 1] =
167 parent->children[j];
168 parent->num_children--;
169 break;
170 }
171
172 /* search for previous sibling that points to this node and
173 * remove the reference
174 */
175 tc_node = ice_sched_get_tc_node(pi, node->tc_num);
176 if (!tc_node) {
177 ice_debug(hw, ICE_DBG_SCHED,
178 "Invalid TC number %d\n", node->tc_num);
179 goto err_exit;
180 }
181 p = ice_sched_get_first_node(hw, tc_node, node->tx_sched_layer);
182 while (p) {
183 if (p->sibling == node) {
184 p->sibling = node->sibling;
185 break;
186 }
187 p = p->sibling;
188 }
189 }
190err_exit:
191 /* leaf nodes have no children */
192 if (node->children)
193 devm_kfree(ice_hw_to_dev(hw), node->children);
194 devm_kfree(ice_hw_to_dev(hw), node);
195}
196
197/**
198 * ice_aq_query_sched_res - query scheduler resource
199 * @hw: pointer to the hw struct
200 * @buf_size: buffer size in bytes
201 * @buf: pointer to buffer
202 * @cd: pointer to command details structure or NULL
203 *
204 * Query scheduler resource allocation (0x0412)
205 */
206static enum ice_status
207ice_aq_query_sched_res(struct ice_hw *hw, u16 buf_size,
208 struct ice_aqc_query_txsched_res_resp *buf,
209 struct ice_sq_cd *cd)
210{
211 struct ice_aq_desc desc;
212
213 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_sched_res);
214 return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
215}
216
217/**
218 * ice_sched_clear_tx_topo - clears the schduler tree nodes
219 * @pi: port information structure
220 *
221 * This function removes all the nodes from HW as well as from SW DB.
222 */
223static void ice_sched_clear_tx_topo(struct ice_port_info *pi)
224{
225 struct ice_sched_agg_info *agg_info;
226 struct ice_sched_vsi_info *vsi_elem;
227 struct ice_sched_agg_info *atmp;
228 struct ice_sched_vsi_info *tmp;
229 struct ice_hw *hw;
230
231 if (!pi)
232 return;
233
234 hw = pi->hw;
235
236 list_for_each_entry_safe(agg_info, atmp, &pi->agg_list, list_entry) {
237 struct ice_sched_agg_vsi_info *agg_vsi_info;
238 struct ice_sched_agg_vsi_info *vtmp;
239
240 list_for_each_entry_safe(agg_vsi_info, vtmp,
241 &agg_info->agg_vsi_list, list_entry) {
242 list_del(&agg_vsi_info->list_entry);
243 devm_kfree(ice_hw_to_dev(hw), agg_vsi_info);
244 }
245 }
246
247 /* remove the vsi list */
248 list_for_each_entry_safe(vsi_elem, tmp, &pi->vsi_info_list,
249 list_entry) {
250 list_del(&vsi_elem->list_entry);
251 devm_kfree(ice_hw_to_dev(hw), vsi_elem);
252 }
253
254 if (pi->root) {
255 ice_free_sched_node(pi, pi->root);
256 pi->root = NULL;
257 }
258}
259
260/**
261 * ice_sched_clear_port - clear the scheduler elements from SW DB for a port
262 * @pi: port information structure
263 *
264 * Cleanup scheduling elements from SW DB
265 */
266static void ice_sched_clear_port(struct ice_port_info *pi)
267{
268 if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
269 return;
270
271 pi->port_state = ICE_SCHED_PORT_STATE_INIT;
272 mutex_lock(&pi->sched_lock);
273 ice_sched_clear_tx_topo(pi);
274 mutex_unlock(&pi->sched_lock);
275 mutex_destroy(&pi->sched_lock);
276}
277
278/**
279 * ice_sched_cleanup_all - cleanup scheduler elements from SW DB for all ports
280 * @hw: pointer to the hw struct
281 *
282 * Cleanup scheduling elements from SW DB for all the ports
283 */
284void ice_sched_cleanup_all(struct ice_hw *hw)
285{
286 if (!hw || !hw->port_info)
287 return;
288
289 if (hw->layer_info)
290 devm_kfree(ice_hw_to_dev(hw), hw->layer_info);
291
292 ice_sched_clear_port(hw->port_info);
293
294 hw->num_tx_sched_layers = 0;
295 hw->num_tx_sched_phys_layers = 0;
296 hw->flattened_layers = 0;
297 hw->max_cgds = 0;
298}
299
300/**
301 * ice_sched_query_res_alloc - query the FW for num of logical sched layers
302 * @hw: pointer to the HW struct
303 *
304 * query FW for allocated scheduler resources and store in HW struct
305 */
306enum ice_status ice_sched_query_res_alloc(struct ice_hw *hw)
307{
308 struct ice_aqc_query_txsched_res_resp *buf;
309 enum ice_status status = 0;
310
311 if (hw->layer_info)
312 return status;
313
314 buf = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*buf), GFP_KERNEL);
315 if (!buf)
316 return ICE_ERR_NO_MEMORY;
317
318 status = ice_aq_query_sched_res(hw, sizeof(*buf), buf, NULL);
319 if (status)
320 goto sched_query_out;
321
322 hw->num_tx_sched_layers = le16_to_cpu(buf->sched_props.logical_levels);
323 hw->num_tx_sched_phys_layers =
324 le16_to_cpu(buf->sched_props.phys_levels);
325 hw->flattened_layers = buf->sched_props.flattening_bitmap;
326 hw->max_cgds = buf->sched_props.max_pf_cgds;
327
328 hw->layer_info = devm_kmemdup(ice_hw_to_dev(hw), buf->layer_props,
329 (hw->num_tx_sched_layers *
330 sizeof(*hw->layer_info)),
331 GFP_KERNEL);
332 if (!hw->layer_info) {
333 status = ICE_ERR_NO_MEMORY;
334 goto sched_query_out;
335 }
336
337sched_query_out:
338 devm_kfree(ice_hw_to_dev(hw), buf);
339 return status;
340}