File Index
Files and directories
Sign in
FILE

hinic3_hw_comm.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c C
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
  3
  4#include <linux/delay.h>
  5
  6#include "hinic3_cmdq.h"
  7#include "hinic3_hw_comm.h"
  8#include "hinic3_hwdev.h"
  9#include "hinic3_hwif.h"
 10#include "hinic3_mbox.h"
 11
 12int hinic3_set_interrupt_cfg_direct(struct hinic3_hwdev *hwdev,
 13				    const struct hinic3_interrupt_info *info)
 14{
 15	struct comm_cmd_cfg_msix_ctrl_reg msix_cfg = {};
 16	struct mgmt_msg_params msg_params = {};
 17	int err;
 18
 19	msix_cfg.func_id = hinic3_global_func_id(hwdev);
 20	msix_cfg.msix_index = info->msix_index;
 21	msix_cfg.opcode = MGMT_MSG_CMD_OP_SET;
 22
 23	msix_cfg.lli_credit_cnt = info->lli_credit_limit;
 24	msix_cfg.lli_timer_cnt = info->lli_timer_cfg;
 25	msix_cfg.pending_cnt = info->pending_limit;
 26	msix_cfg.coalesce_timer_cnt = info->coalesc_timer_cfg;
 27	msix_cfg.resend_timer_cnt = info->resend_timer_cfg;
 28
 29	mgmt_msg_params_init_default(&msg_params, &msix_cfg, sizeof(msix_cfg));
 30
 31	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
 32				       COMM_CMD_CFG_MSIX_CTRL_REG, &msg_params);
 33	if (err || msix_cfg.head.status) {
 34		dev_err(hwdev->dev,
 35			"Failed to set interrupt config, err: %d, status: 0x%x\n",
 36			err, msix_cfg.head.status);
 37		return -EINVAL;
 38	}
 39
 40	return 0;
 41}
 42
 43int hinic3_func_reset(struct hinic3_hwdev *hwdev, u16 func_id, u64 reset_flag)
 44{
 45	struct comm_cmd_func_reset func_reset = {};
 46	struct mgmt_msg_params msg_params = {};
 47	int err;
 48
 49	func_reset.func_id = func_id;
 50	func_reset.reset_flag = reset_flag;
 51
 52	mgmt_msg_params_init_default(&msg_params, &func_reset,
 53				     sizeof(func_reset));
 54
 55	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
 56				       COMM_CMD_FUNC_RESET, &msg_params);
 57	if (err || func_reset.head.status) {
 58		dev_err(hwdev->dev, "Failed to reset func resources, reset_flag 0x%llx, err: %d, status: 0x%x\n",
 59			reset_flag, err, func_reset.head.status);
 60		return -EIO;
 61	}
 62
 63	return 0;
 64}
 65
 66static int hinic3_comm_features_nego(struct hinic3_hwdev *hwdev, u8 opcode,
 67				     u64 *s_feature, u16 size)
 68{
 69	struct comm_cmd_feature_nego feature_nego = {};
 70	struct mgmt_msg_params msg_params = {};
 71	int err;
 72
 73	feature_nego.func_id = hinic3_global_func_id(hwdev);
 74	feature_nego.opcode = opcode;
 75	if (opcode == MGMT_MSG_CMD_OP_SET)
 76		memcpy(feature_nego.s_feature, s_feature,
 77		       array_size(size, sizeof(u64)));
 78
 79	mgmt_msg_params_init_default(&msg_params, &feature_nego,
 80				     sizeof(feature_nego));
 81
 82	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
 83				       COMM_CMD_FEATURE_NEGO, &msg_params);
 84	if (err || feature_nego.head.status) {
 85		dev_err(hwdev->dev, "Failed to negotiate feature, err: %d, status: 0x%x\n",
 86			err, feature_nego.head.status);
 87		return -EINVAL;
 88	}
 89
 90	if (opcode == MGMT_MSG_CMD_OP_GET)
 91		memcpy(s_feature, feature_nego.s_feature,
 92		       array_size(size, sizeof(u64)));
 93
 94	return 0;
 95}
 96
 97int hinic3_get_comm_features(struct hinic3_hwdev *hwdev, u64 *s_feature,
 98			     u16 size)
 99{
100	return hinic3_comm_features_nego(hwdev, MGMT_MSG_CMD_OP_GET, s_feature,
101					 size);
102}
103
104int hinic3_set_comm_features(struct hinic3_hwdev *hwdev, u64 *s_feature,
105			     u16 size)
106{
107	return hinic3_comm_features_nego(hwdev, MGMT_MSG_CMD_OP_SET, s_feature,
108					 size);
109}
110
111int hinic3_get_global_attr(struct hinic3_hwdev *hwdev,
112			   struct comm_global_attr *attr)
113{
114	struct comm_cmd_get_glb_attr get_attr = {};
115	struct mgmt_msg_params msg_params = {};
116	int err;
117
118	mgmt_msg_params_init_default(&msg_params, &get_attr, sizeof(get_attr));
119
120	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
121				       COMM_CMD_GET_GLOBAL_ATTR, &msg_params);
122	if (err || get_attr.head.status) {
123		dev_err(hwdev->dev,
124			"Failed to get global attribute, err: %d, status: 0x%x\n",
125			err, get_attr.head.status);
126		return -EIO;
127	}
128
129	memcpy(attr, &get_attr.attr, sizeof(*attr));
130
131	return 0;
132}
133
134int hinic3_set_func_svc_used_state(struct hinic3_hwdev *hwdev, u16 svc_type,
135				   u8 state)
136{
137	struct comm_cmd_set_func_svc_used_state used_state = {};
138	struct mgmt_msg_params msg_params = {};
139	int err;
140
141	used_state.func_id = hinic3_global_func_id(hwdev);
142	used_state.svc_type = svc_type;
143	used_state.used_state = state;
144
145	mgmt_msg_params_init_default(&msg_params, &used_state,
146				     sizeof(used_state));
147
148	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
149				       COMM_CMD_SET_FUNC_SVC_USED_STATE,
150				       &msg_params);
151	if (err || used_state.head.status) {
152		dev_err(hwdev->dev,
153			"Failed to set func service used state, err: %d, status: 0x%x\n",
154			err, used_state.head.status);
155		return -EIO;
156	}
157
158	return 0;
159}
160
161int hinic3_set_dma_attr_tbl(struct hinic3_hwdev *hwdev, u8 entry_idx, u8 st,
162			    u8 at, u8 ph, u8 no_snooping, u8 tph_en)
163{
164	struct comm_cmd_set_dma_attr dma_attr = {};
165	struct mgmt_msg_params msg_params = {};
166	int err;
167
168	dma_attr.func_id = hinic3_global_func_id(hwdev);
169	dma_attr.entry_idx = entry_idx;
170	dma_attr.st = st;
171	dma_attr.at = at;
172	dma_attr.ph = ph;
173	dma_attr.no_snooping = no_snooping;
174	dma_attr.tph_en = tph_en;
175
176	mgmt_msg_params_init_default(&msg_params, &dma_attr, sizeof(dma_attr));
177
178	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
179				       COMM_CMD_SET_DMA_ATTR, &msg_params);
180	if (err || dma_attr.head.status) {
181		dev_err(hwdev->dev, "Failed to set dma attr, err: %d, status: 0x%x\n",
182			err, dma_attr.head.status);
183		return -EIO;
184	}
185
186	return 0;
187}
188
189int hinic3_set_wq_page_size(struct hinic3_hwdev *hwdev, u16 func_idx,
190			    u32 page_size)
191{
192	struct comm_cmd_cfg_wq_page_size page_size_info = {};
193	struct mgmt_msg_params msg_params = {};
194	int err;
195
196	page_size_info.func_id = func_idx;
197	page_size_info.page_size = ilog2(page_size / HINIC3_MIN_PAGE_SIZE);
198	page_size_info.opcode = MGMT_MSG_CMD_OP_SET;
199
200	mgmt_msg_params_init_default(&msg_params, &page_size_info,
201				     sizeof(page_size_info));
202
203	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
204				       COMM_CMD_CFG_PAGESIZE, &msg_params);
205	if (err || page_size_info.head.status) {
206		dev_err(hwdev->dev,
207			"Failed to set wq page size, err: %d, status: 0x%x\n",
208			err, page_size_info.head.status);
209		return -EFAULT;
210	}
211
212	return 0;
213}
214
215int hinic3_set_cmdq_depth(struct hinic3_hwdev *hwdev, u16 cmdq_depth)
216{
217	struct comm_cmd_set_root_ctxt root_ctxt = {};
218	struct mgmt_msg_params msg_params = {};
219	int err;
220
221	root_ctxt.func_id = hinic3_global_func_id(hwdev);
222
223	root_ctxt.set_cmdq_depth = 1;
224	root_ctxt.cmdq_depth = ilog2(cmdq_depth);
225
226	mgmt_msg_params_init_default(&msg_params, &root_ctxt,
227				     sizeof(root_ctxt));
228
229	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
230				       COMM_CMD_SET_VAT, &msg_params);
231	if (err || root_ctxt.head.status) {
232		dev_err(hwdev->dev,
233			"Failed to set cmdq depth, err: %d, status: 0x%x\n",
234			err, root_ctxt.head.status);
235		return -EFAULT;
236	}
237
238	return 0;
239}
240
241#define HINIC3_WAIT_CMDQ_IDLE_TIMEOUT    5000
242
243static enum hinic3_wait_return check_cmdq_stop_handler(void *priv_data)
244{
245	struct hinic3_hwdev *hwdev = priv_data;
246	enum hinic3_cmdq_type cmdq_type;
247	struct hinic3_cmdqs *cmdqs;
248
249	cmdqs = hwdev->cmdqs;
250	for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) {
251		if (!hinic3_cmdq_idle(&cmdqs->cmdq[cmdq_type]))
252			return HINIC3_WAIT_PROCESS_WAITING;
253	}
254
255	return HINIC3_WAIT_PROCESS_CPL;
256}
257
258static int wait_cmdq_stop(struct hinic3_hwdev *hwdev)
259{
260	struct hinic3_cmdqs *cmdqs = hwdev->cmdqs;
261	enum hinic3_cmdq_type cmdq_type;
262	int err;
263
264	if (!(cmdqs->status & HINIC3_CMDQ_ENABLE))
265		return 0;
266
267	cmdqs->status &= ~HINIC3_CMDQ_ENABLE;
268	err = hinic3_wait_for_timeout(hwdev, check_cmdq_stop_handler,
269				      HINIC3_WAIT_CMDQ_IDLE_TIMEOUT,
270				      USEC_PER_MSEC);
271
272	if (err)
273		goto err_reenable_cmdq;
274
275	return 0;
276
277err_reenable_cmdq:
278	for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) {
279		if (!hinic3_cmdq_idle(&cmdqs->cmdq[cmdq_type]))
280			dev_err(hwdev->dev, "Cmdq %d is busy\n", cmdq_type);
281	}
282	cmdqs->status |= HINIC3_CMDQ_ENABLE;
283
284	return err;
285}
286
287int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev)
288{
289	struct comm_cmd_clear_resource clear_db = {};
290	struct comm_cmd_clear_resource clr_res = {};
291	struct hinic3_hwif *hwif = hwdev->hwif;
292	struct mgmt_msg_params msg_params = {};
293	int ret = 0;
294	int err;
295
296	err = wait_cmdq_stop(hwdev);
297	if (err) {
298		dev_warn(hwdev->dev, "CMDQ is still working, CMDQ timeout value is unreasonable\n");
299		ret = err;
300	}
301
302	hinic3_toggle_doorbell(hwif, DISABLE_DOORBELL);
303
304	clear_db.func_id = hwif->attr.func_global_idx;
305	mgmt_msg_params_init_default(&msg_params, &clear_db, sizeof(clear_db));
306	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
307				       COMM_CMD_FLUSH_DOORBELL, &msg_params);
308	if (err || clear_db.head.status) {
309		dev_warn(hwdev->dev, "Failed to flush doorbell, err: %d, status: 0x%x\n",
310			 err, clear_db.head.status);
311		if (err)
312			ret = err;
313		else
314			ret = -EFAULT;
315	}
316
317	clr_res.func_id = hwif->attr.func_global_idx;
318	msg_params.buf_in = &clr_res;
319	msg_params.in_size = sizeof(clr_res);
320	err = hinic3_send_mbox_to_mgmt_no_ack(hwdev, MGMT_MOD_COMM,
321					      COMM_CMD_START_FLUSH,
322					      &msg_params);
323	if (err) {
324		dev_warn(hwdev->dev, "Failed to notice flush message, err: %d\n",
325			 err);
326		ret = err;
327	}
328
329	hinic3_toggle_doorbell(hwif, ENABLE_DOORBELL);
330
331	err = hinic3_reinit_cmdq_ctxts(hwdev);
332	if (err) {
333		dev_warn(hwdev->dev, "Failed to reinit cmdq\n");
334		ret = err;
335	}
336
337	return ret;
338}
339
340static int get_hw_rx_buf_size_idx(int rx_buf_sz, u16 *buf_sz_idx)
341{
342	/* Supported RX buffer sizes in bytes. Configured by array index. */
343	static const int supported_sizes[16] = {
344		[0] = 32,     [1] = 64,     [2] = 96,     [3] = 128,
345		[4] = 192,    [5] = 256,    [6] = 384,    [7] = 512,
346		[8] = 768,    [9] = 1024,   [10] = 1536,  [11] = 2048,
347		[12] = 3072,  [13] = 4096,  [14] = 8192,  [15] = 16384,
348	};
349	u16 idx;
350
351	/* Scan from biggest to smallest. Choose supported size that is equal or
352	 * smaller. For smaller value HW will under-utilize posted buffers. For
353	 * bigger value HW may overrun posted buffers.
354	 */
355	idx = ARRAY_SIZE(supported_sizes);
356	while (idx > 0) {
357		idx--;
358		if (supported_sizes[idx] <= rx_buf_sz) {
359			*buf_sz_idx = idx;
360			return 0;
361		}
362	}
363
364	return -EINVAL;
365}
366
367int hinic3_set_root_ctxt(struct hinic3_hwdev *hwdev, u32 rq_depth, u32 sq_depth,
368			 int rx_buf_sz)
369{
370	struct comm_cmd_set_root_ctxt root_ctxt = {};
371	struct mgmt_msg_params msg_params = {};
372	u16 buf_sz_idx;
373	int err;
374
375	err = get_hw_rx_buf_size_idx(rx_buf_sz, &buf_sz_idx);
376	if (err)
377		return err;
378
379	root_ctxt.func_id = hinic3_global_func_id(hwdev);
380
381	root_ctxt.set_cmdq_depth = 0;
382	root_ctxt.cmdq_depth = 0;
383
384	root_ctxt.lro_en = 1;
385
386	root_ctxt.rq_depth  = ilog2(rq_depth);
387	root_ctxt.rx_buf_sz = buf_sz_idx;
388	root_ctxt.sq_depth  = ilog2(sq_depth);
389
390	mgmt_msg_params_init_default(&msg_params, &root_ctxt,
391				     sizeof(root_ctxt));
392
393	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
394				       COMM_CMD_SET_VAT, &msg_params);
395	if (err || root_ctxt.head.status) {
396		dev_err(hwdev->dev,
397			"Failed to set root context, err: %d, status: 0x%x\n",
398			err, root_ctxt.head.status);
399		return -EFAULT;
400	}
401
402	return 0;
403}
404
405int hinic3_clean_root_ctxt(struct hinic3_hwdev *hwdev)
406{
407	struct comm_cmd_set_root_ctxt root_ctxt = {};
408	struct mgmt_msg_params msg_params = {};
409	int err;
410
411	root_ctxt.func_id = hinic3_global_func_id(hwdev);
412
413	mgmt_msg_params_init_default(&msg_params, &root_ctxt,
414				     sizeof(root_ctxt));
415
416	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
417				       COMM_CMD_SET_VAT, &msg_params);
418	if (err || root_ctxt.head.status) {
419		dev_err(hwdev->dev,
420			"Failed to set root context, err: %d, status: 0x%x\n",
421			err, root_ctxt.head.status);
422		return -EFAULT;
423	}
424
425	return 0;
426}
~/ Read-only file preview.