xref: /linux/drivers/net/ethernet/intel/ice/ice_fwlog.c (revision 9e56ff53b4115875667760445b028357848b4748)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022, Intel Corporation. */
3 
4 #include <linux/vmalloc.h>
5 #include "ice.h"
6 #include "ice_common.h"
7 #include "ice_fwlog.h"
8 
9 bool ice_fwlog_ring_full(struct ice_fwlog_ring *rings)
10 {
11 	u16 head, tail;
12 
13 	head = rings->head;
14 	tail = rings->tail;
15 
16 	if (head < tail && (tail - head == (rings->size - 1)))
17 		return true;
18 	else if (head > tail && (tail == (head - 1)))
19 		return true;
20 
21 	return false;
22 }
23 
24 bool ice_fwlog_ring_empty(struct ice_fwlog_ring *rings)
25 {
26 	return rings->head == rings->tail;
27 }
28 
29 void ice_fwlog_ring_increment(u16 *item, u16 size)
30 {
31 	*item = (*item + 1) & (size - 1);
32 }
33 
34 static int ice_fwlog_alloc_ring_buffs(struct ice_fwlog_ring *rings)
35 {
36 	int i, nr_bytes;
37 	u8 *mem;
38 
39 	nr_bytes = rings->size * ICE_AQ_MAX_BUF_LEN;
40 	mem = vzalloc(nr_bytes);
41 	if (!mem)
42 		return -ENOMEM;
43 
44 	for (i = 0; i < rings->size; i++) {
45 		struct ice_fwlog_data *ring = &rings->rings[i];
46 
47 		ring->data_size = ICE_AQ_MAX_BUF_LEN;
48 		ring->data = mem;
49 		mem += ICE_AQ_MAX_BUF_LEN;
50 	}
51 
52 	return 0;
53 }
54 
55 static void ice_fwlog_free_ring_buffs(struct ice_fwlog_ring *rings)
56 {
57 	int i;
58 
59 	for (i = 0; i < rings->size; i++) {
60 		struct ice_fwlog_data *ring = &rings->rings[i];
61 
62 		/* the first ring is the base memory for the whole range so
63 		 * free it
64 		 */
65 		if (!i)
66 			vfree(ring->data);
67 
68 		ring->data = NULL;
69 		ring->data_size = 0;
70 	}
71 }
72 
73 #define ICE_FWLOG_INDEX_TO_BYTES(n) ((128 * 1024) << (n))
74 /**
75  * ice_fwlog_realloc_rings - reallocate the FW log rings
76  * @hw: pointer to the HW structure
77  * @index: the new index to use to allocate memory for the log data
78  *
79  */
80 void ice_fwlog_realloc_rings(struct ice_hw *hw, int index)
81 {
82 	struct ice_fwlog_ring ring;
83 	int status, ring_size;
84 
85 	/* convert the number of bytes into a number of 4K buffers. externally
86 	 * the driver presents the interface to the FW log data as a number of
87 	 * bytes because that's easy for users to understand. internally the
88 	 * driver uses a ring of buffers because the driver doesn't know where
89 	 * the beginning and end of any line of log data is so the driver has
90 	 * to overwrite data as complete blocks. when the data is returned to
91 	 * the user the driver knows that the data is correct and the FW log
92 	 * can be correctly parsed by the tools
93 	 */
94 	ring_size = ICE_FWLOG_INDEX_TO_BYTES(index) / ICE_AQ_MAX_BUF_LEN;
95 	if (ring_size == hw->fwlog_ring.size)
96 		return;
97 
98 	/* allocate space for the new rings and buffers then release the
99 	 * old rings and buffers. that way if we don't have enough
100 	 * memory then we at least have what we had before
101 	 */
102 	ring.rings = kcalloc(ring_size, sizeof(*ring.rings), GFP_KERNEL);
103 	if (!ring.rings)
104 		return;
105 
106 	ring.size = ring_size;
107 
108 	status = ice_fwlog_alloc_ring_buffs(&ring);
109 	if (status) {
110 		dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log ring data buffers\n");
111 		ice_fwlog_free_ring_buffs(&ring);
112 		kfree(ring.rings);
113 		return;
114 	}
115 
116 	ice_fwlog_free_ring_buffs(&hw->fwlog_ring);
117 	kfree(hw->fwlog_ring.rings);
118 
119 	hw->fwlog_ring.rings = ring.rings;
120 	hw->fwlog_ring.size = ring.size;
121 	hw->fwlog_ring.index = index;
122 	hw->fwlog_ring.head = 0;
123 	hw->fwlog_ring.tail = 0;
124 }
125 
126 /**
127  * ice_fwlog_init - Initialize FW logging configuration
128  * @hw: pointer to the HW structure
129  *
130  * This function should be called on driver initialization during
131  * ice_init_hw().
132  */
133 int ice_fwlog_init(struct ice_hw *hw)
134 {
135 	/* only support fw log commands on PF 0 */
136 	if (hw->bus.func)
137 		return -EINVAL;
138 
139 	ice_fwlog_set_supported(hw);
140 
141 	if (ice_fwlog_supported(hw)) {
142 		int status;
143 
144 		/* read the current config from the FW and store it */
145 		status = ice_fwlog_get(hw, &hw->fwlog_cfg);
146 		if (status)
147 			return status;
148 
149 		hw->fwlog_ring.rings = kcalloc(ICE_FWLOG_RING_SIZE_DFLT,
150 					       sizeof(*hw->fwlog_ring.rings),
151 					       GFP_KERNEL);
152 		if (!hw->fwlog_ring.rings) {
153 			dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log rings\n");
154 			return -ENOMEM;
155 		}
156 
157 		hw->fwlog_ring.size = ICE_FWLOG_RING_SIZE_DFLT;
158 		hw->fwlog_ring.index = ICE_FWLOG_RING_SIZE_INDEX_DFLT;
159 
160 		status = ice_fwlog_alloc_ring_buffs(&hw->fwlog_ring);
161 		if (status) {
162 			dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log ring data buffers\n");
163 			ice_fwlog_free_ring_buffs(&hw->fwlog_ring);
164 			kfree(hw->fwlog_ring.rings);
165 			return status;
166 		}
167 
168 		ice_debugfs_fwlog_init(hw->back);
169 	} else {
170 		dev_warn(ice_hw_to_dev(hw), "FW logging is not supported in this NVM image. Please update the NVM to get FW log support\n");
171 	}
172 
173 	return 0;
174 }
175 
176 /**
177  * ice_fwlog_deinit - unroll FW logging configuration
178  * @hw: pointer to the HW structure
179  *
180  * This function should be called in ice_deinit_hw().
181  */
182 void ice_fwlog_deinit(struct ice_hw *hw)
183 {
184 	struct ice_pf *pf = hw->back;
185 	int status;
186 
187 	/* only support fw log commands on PF 0 */
188 	if (hw->bus.func)
189 		return;
190 
191 	/* make sure FW logging is disabled to not put the FW in a weird state
192 	 * for the next driver load
193 	 */
194 	hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_ARQ_ENA;
195 	status = ice_fwlog_set(hw, &hw->fwlog_cfg);
196 	if (status)
197 		dev_warn(ice_hw_to_dev(hw), "Unable to turn off FW logging, status: %d\n",
198 			 status);
199 
200 	kfree(pf->ice_debugfs_pf_fwlog_modules);
201 
202 	pf->ice_debugfs_pf_fwlog_modules = NULL;
203 
204 	status = ice_fwlog_unregister(hw);
205 	if (status)
206 		dev_warn(ice_hw_to_dev(hw), "Unable to unregister FW logging, status: %d\n",
207 			 status);
208 
209 	if (hw->fwlog_ring.rings) {
210 		ice_fwlog_free_ring_buffs(&hw->fwlog_ring);
211 		kfree(hw->fwlog_ring.rings);
212 	}
213 }
214 
215 /**
216  * ice_fwlog_supported - Cached for whether FW supports FW logging or not
217  * @hw: pointer to the HW structure
218  *
219  * This will always return false if called before ice_init_hw(), so it must be
220  * called after ice_init_hw().
221  */
222 bool ice_fwlog_supported(struct ice_hw *hw)
223 {
224 	return hw->fwlog_supported;
225 }
226 
227 /**
228  * ice_aq_fwlog_set - Set FW logging configuration AQ command (0xFF30)
229  * @hw: pointer to the HW structure
230  * @entries: entries to configure
231  * @num_entries: number of @entries
232  * @options: options from ice_fwlog_cfg->options structure
233  * @log_resolution: logging resolution
234  */
235 static int
236 ice_aq_fwlog_set(struct ice_hw *hw, struct ice_fwlog_module_entry *entries,
237 		 u16 num_entries, u16 options, u16 log_resolution)
238 {
239 	struct ice_aqc_fw_log_cfg_resp *fw_modules;
240 	struct ice_aqc_fw_log *cmd;
241 	struct ice_aq_desc desc;
242 	int status;
243 	int i;
244 
245 	fw_modules = kcalloc(num_entries, sizeof(*fw_modules), GFP_KERNEL);
246 	if (!fw_modules)
247 		return -ENOMEM;
248 
249 	for (i = 0; i < num_entries; i++) {
250 		fw_modules[i].module_identifier =
251 			cpu_to_le16(entries[i].module_id);
252 		fw_modules[i].log_level = entries[i].log_level;
253 	}
254 
255 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_config);
256 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
257 
258 	cmd = &desc.params.fw_log;
259 
260 	cmd->cmd_flags = ICE_AQC_FW_LOG_CONF_SET_VALID;
261 	cmd->ops.cfg.log_resolution = cpu_to_le16(log_resolution);
262 	cmd->ops.cfg.mdl_cnt = cpu_to_le16(num_entries);
263 
264 	if (options & ICE_FWLOG_OPTION_ARQ_ENA)
265 		cmd->cmd_flags |= ICE_AQC_FW_LOG_CONF_AQ_EN;
266 	if (options & ICE_FWLOG_OPTION_UART_ENA)
267 		cmd->cmd_flags |= ICE_AQC_FW_LOG_CONF_UART_EN;
268 
269 	status = ice_aq_send_cmd(hw, &desc, fw_modules,
270 				 sizeof(*fw_modules) * num_entries,
271 				 NULL);
272 
273 	kfree(fw_modules);
274 
275 	return status;
276 }
277 
278 /**
279  * ice_fwlog_set - Set the firmware logging settings
280  * @hw: pointer to the HW structure
281  * @cfg: config used to set firmware logging
282  *
283  * This function should be called whenever the driver needs to set the firmware
284  * logging configuration. It can be called on initialization, reset, or during
285  * runtime.
286  *
287  * If the PF wishes to receive FW logging then it must register via
288  * ice_fwlog_register. Note, that ice_fwlog_register does not need to be called
289  * for init.
290  */
291 int ice_fwlog_set(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
292 {
293 	if (!ice_fwlog_supported(hw))
294 		return -EOPNOTSUPP;
295 
296 	return ice_aq_fwlog_set(hw, cfg->module_entries,
297 				ICE_AQC_FW_LOG_ID_MAX, cfg->options,
298 				cfg->log_resolution);
299 }
300 
301 /**
302  * ice_aq_fwlog_get - Get the current firmware logging configuration (0xFF32)
303  * @hw: pointer to the HW structure
304  * @cfg: firmware logging configuration to populate
305  */
306 static int ice_aq_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
307 {
308 	struct ice_aqc_fw_log_cfg_resp *fw_modules;
309 	struct ice_aqc_fw_log *cmd;
310 	struct ice_aq_desc desc;
311 	u16 module_id_cnt;
312 	int status;
313 	void *buf;
314 	int i;
315 
316 	memset(cfg, 0, sizeof(*cfg));
317 
318 	buf = kzalloc(ICE_AQ_MAX_BUF_LEN, GFP_KERNEL);
319 	if (!buf)
320 		return -ENOMEM;
321 
322 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_query);
323 	cmd = &desc.params.fw_log;
324 
325 	cmd->cmd_flags = ICE_AQC_FW_LOG_AQ_QUERY;
326 
327 	status = ice_aq_send_cmd(hw, &desc, buf, ICE_AQ_MAX_BUF_LEN, NULL);
328 	if (status) {
329 		ice_debug(hw, ICE_DBG_FW_LOG, "Failed to get FW log configuration\n");
330 		goto status_out;
331 	}
332 
333 	module_id_cnt = le16_to_cpu(cmd->ops.cfg.mdl_cnt);
334 	if (module_id_cnt < ICE_AQC_FW_LOG_ID_MAX) {
335 		ice_debug(hw, ICE_DBG_FW_LOG, "FW returned less than the expected number of FW log module IDs\n");
336 	} else if (module_id_cnt > ICE_AQC_FW_LOG_ID_MAX) {
337 		ice_debug(hw, ICE_DBG_FW_LOG, "FW returned more than expected number of FW log module IDs, setting module_id_cnt to software expected max %u\n",
338 			  ICE_AQC_FW_LOG_ID_MAX);
339 		module_id_cnt = ICE_AQC_FW_LOG_ID_MAX;
340 	}
341 
342 	cfg->log_resolution = le16_to_cpu(cmd->ops.cfg.log_resolution);
343 	if (cmd->cmd_flags & ICE_AQC_FW_LOG_CONF_AQ_EN)
344 		cfg->options |= ICE_FWLOG_OPTION_ARQ_ENA;
345 	if (cmd->cmd_flags & ICE_AQC_FW_LOG_CONF_UART_EN)
346 		cfg->options |= ICE_FWLOG_OPTION_UART_ENA;
347 	if (cmd->cmd_flags & ICE_AQC_FW_LOG_QUERY_REGISTERED)
348 		cfg->options |= ICE_FWLOG_OPTION_IS_REGISTERED;
349 
350 	fw_modules = (struct ice_aqc_fw_log_cfg_resp *)buf;
351 
352 	for (i = 0; i < module_id_cnt; i++) {
353 		struct ice_aqc_fw_log_cfg_resp *fw_module = &fw_modules[i];
354 
355 		cfg->module_entries[i].module_id =
356 			le16_to_cpu(fw_module->module_identifier);
357 		cfg->module_entries[i].log_level = fw_module->log_level;
358 	}
359 
360 status_out:
361 	kfree(buf);
362 	return status;
363 }
364 
365 /**
366  * ice_fwlog_get - Get the firmware logging settings
367  * @hw: pointer to the HW structure
368  * @cfg: config to populate based on current firmware logging settings
369  */
370 int ice_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
371 {
372 	if (!ice_fwlog_supported(hw))
373 		return -EOPNOTSUPP;
374 
375 	return ice_aq_fwlog_get(hw, cfg);
376 }
377 
378 /**
379  * ice_aq_fwlog_register - Register PF for firmware logging events (0xFF31)
380  * @hw: pointer to the HW structure
381  * @reg: true to register and false to unregister
382  */
383 static int ice_aq_fwlog_register(struct ice_hw *hw, bool reg)
384 {
385 	struct ice_aq_desc desc;
386 
387 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_register);
388 
389 	if (reg)
390 		desc.params.fw_log.cmd_flags = ICE_AQC_FW_LOG_AQ_REGISTER;
391 
392 	return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
393 }
394 
395 /**
396  * ice_fwlog_register - Register the PF for firmware logging
397  * @hw: pointer to the HW structure
398  *
399  * After this call the PF will start to receive firmware logging based on the
400  * configuration set in ice_fwlog_set.
401  */
402 int ice_fwlog_register(struct ice_hw *hw)
403 {
404 	int status;
405 
406 	if (!ice_fwlog_supported(hw))
407 		return -EOPNOTSUPP;
408 
409 	status = ice_aq_fwlog_register(hw, true);
410 	if (status)
411 		ice_debug(hw, ICE_DBG_FW_LOG, "Failed to register for firmware logging events over ARQ\n");
412 	else
413 		hw->fwlog_cfg.options |= ICE_FWLOG_OPTION_IS_REGISTERED;
414 
415 	return status;
416 }
417 
418 /**
419  * ice_fwlog_unregister - Unregister the PF from firmware logging
420  * @hw: pointer to the HW structure
421  */
422 int ice_fwlog_unregister(struct ice_hw *hw)
423 {
424 	int status;
425 
426 	if (!ice_fwlog_supported(hw))
427 		return -EOPNOTSUPP;
428 
429 	status = ice_aq_fwlog_register(hw, false);
430 	if (status)
431 		ice_debug(hw, ICE_DBG_FW_LOG, "Failed to unregister from firmware logging events over ARQ\n");
432 	else
433 		hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_IS_REGISTERED;
434 
435 	return status;
436 }
437 
438 /**
439  * ice_fwlog_set_supported - Set if FW logging is supported by FW
440  * @hw: pointer to the HW struct
441  *
442  * If FW returns success to the ice_aq_fwlog_get call then it supports FW
443  * logging, else it doesn't. Set the fwlog_supported flag accordingly.
444  *
445  * This function is only meant to be called during driver init to determine if
446  * the FW support FW logging.
447  */
448 void ice_fwlog_set_supported(struct ice_hw *hw)
449 {
450 	struct ice_fwlog_cfg *cfg;
451 	int status;
452 
453 	hw->fwlog_supported = false;
454 
455 	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
456 	if (!cfg)
457 		return;
458 
459 	/* don't call ice_fwlog_get() because that would check to see if FW
460 	 * logging is supported which is what the driver is determining now
461 	 */
462 	status = ice_aq_fwlog_get(hw, cfg);
463 	if (status)
464 		ice_debug(hw, ICE_DBG_FW_LOG, "ice_aq_fwlog_get failed, FW logging is not supported on this version of FW, status %d\n",
465 			  status);
466 	else
467 		hw->fwlog_supported = true;
468 
469 	kfree(cfg);
470 }
471