xref: /linux/drivers/fwctl/bnxt/main.c (revision ee1c26323eeb01bca825d102cb7fff6921fa314f)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2026, Broadcom Corporation
4  */
5 
6 #include <linux/auxiliary_bus.h>
7 #include <linux/dma-mapping.h>
8 #include <linux/slab.h>
9 #include <linux/pci.h>
10 #include <linux/fwctl.h>
11 #include <linux/bnxt/hsi.h>
12 #include <linux/bnxt/ulp.h>
13 #include <uapi/fwctl/fwctl.h>
14 #include <uapi/fwctl/bnxt.h>
15 
16 struct bnxtctl_uctx {
17 	struct fwctl_uctx uctx;
18 	u32 uctx_caps;
19 };
20 
21 struct bnxtctl_dev {
22 	struct fwctl_device fwctl;
23 	struct bnxt_aux_priv *aux_priv;
24 };
25 
26 DEFINE_FREE(bnxtctl, struct bnxtctl_dev *, if (_T) fwctl_put(&_T->fwctl))
27 
28 static int bnxtctl_open_uctx(struct fwctl_uctx *uctx)
29 {
30 	struct bnxtctl_uctx *bnxtctl_uctx =
31 		container_of(uctx, struct bnxtctl_uctx, uctx);
32 
33 	bnxtctl_uctx->uctx_caps = BIT(FWCTL_BNXT_INLINE_COMMANDS) |
34 				  BIT(FWCTL_BNXT_QUERY_COMMANDS) |
35 				  BIT(FWCTL_BNXT_SEND_COMMANDS) |
36 				  BIT(FWCTL_BNXT_DMA_COMMANDS);
37 	return 0;
38 }
39 
40 static void bnxtctl_close_uctx(struct fwctl_uctx *uctx)
41 {
42 }
43 
44 static void *bnxtctl_info(struct fwctl_uctx *uctx, size_t *length)
45 {
46 	struct bnxtctl_uctx *bnxtctl_uctx =
47 		container_of(uctx, struct bnxtctl_uctx, uctx);
48 	struct fwctl_info_bnxt *info;
49 
50 	info = kzalloc_obj(*info);
51 	if (!info)
52 		return ERR_PTR(-ENOMEM);
53 
54 	info->uctx_caps = bnxtctl_uctx->uctx_caps;
55 
56 	*length = sizeof(*info);
57 	return info;
58 }
59 
60 #define BNXTCTL_MAX_DMA_FIELDS	4
61 
62 struct bnxtctl_dma_field {
63 	size_t offset;		/* offsetof(hwrm_xxx_input, addr_field) */
64 	enum dma_data_direction dir;
65 	size_t len_offset;	/* offsetof(hwrm_xxx_input, len_field); 0 if the
66 				 * command carries no transfer-length field
67 				 */
68 	u8     len_width;	/* byte width of the length field: 2 or 4 */
69 	u8     len_unit;	/* bytes represented by one unit of the length field */
70 	u32    buf_len;		/* for commands with no length in payload */
71 };
72 
73 struct bnxtctl_cmd_dma_desc {
74 	u16                      req_type;
75 	u8                       num_fields;
76 	u8                       scope_min;
77 	size_t                   req_size;   /* sizeof(struct hwrm_xxx_input) */
78 	struct bnxtctl_dma_field fields[BNXTCTL_MAX_DMA_FIELDS];
79 };
80 
81 /* input struct has an addr/len pair, but len is multiplied by _unit */
82 #define CMD_DATA_UNIT(_struct, _dir, _data, _len, _unit) \
83 	{ .offset = offsetof(_struct, _data),            \
84 	  .dir = _dir,                                   \
85 	  .len_offset = offsetof(_struct, _len),         \
86 	  .len_width = sizeof(((_struct *)0)->_len),     \
87 	  .len_unit = _unit }
88 
89 /* input struct has an addr/len pair with byte length */
90 #define CMD_DATA_SIMPLE(_struct, _dir, _data, _len) \
91 	CMD_DATA_UNIT(_struct, _dir, _data, _len, 1)
92 
93 /* input struct has an addr but the length is fixed */
94 #define CMD_DATA_FIXED(_struct, _dir, _data, _len) \
95 	{ .offset = offsetof(_struct, _data), .dir = _dir, .buf_len = _len }
96 
97 #define CMD_DMAS(_req_type, _scope_min, _struct, _num_fields, ...) \
98 	{                                                          \
99 		.req_type = _req_type,                             \
100 		.scope_min = _scope_min,                           \
101 		.req_size = sizeof(_struct),                       \
102 		.num_fields = _num_fields,                         \
103 		.fields = { __VA_ARGS__ },                         \
104 	}
105 
106 #define CMD_DMA_LEN(_req_type, _scope_min, _dir, _struct, _data, _len) \
107 	CMD_DMAS(_req_type, _scope_min, _struct, 1,                    \
108 		 CMD_DATA_SIMPLE(_struct, _dir, _data, _len))
109 
110 /*
111  * Per-command DMA buffer descriptor table for HWRM commands that
112  * carry __le64 DMA address fields in their input
113  */
114 static const struct bnxtctl_cmd_dma_desc bnxtctl_dma_cmds[] = {
115 	CMD_DMA_LEN(HWRM_NVM_SET_VARIABLE, FWCTL_RPC_CONFIGURATION,
116 		    DMA_TO_DEVICE,
117 		    struct hwrm_nvm_set_variable_input, src_data_addr,
118 		    data_len),
119 	CMD_DMA_LEN(HWRM_NVM_GET_VARIABLE, FWCTL_RPC_CONFIGURATION,
120 		    DMA_FROM_DEVICE,
121 		    struct hwrm_nvm_get_variable_input, dest_data_addr,
122 		    data_len),
123 	CMD_DMA_LEN(HWRM_NVM_READ, FWCTL_RPC_DEBUG_READ_ONLY,
124 		    DMA_FROM_DEVICE, struct hwrm_nvm_read_input,
125 		    host_dest_addr, len),
126 	CMD_DMAS(HWRM_NVM_GET_DIR_ENTRIES, FWCTL_RPC_DEBUG_READ_ONLY,
127 		 struct hwrm_nvm_get_dir_entries_input, 1,
128 		 CMD_DATA_FIXED(struct hwrm_nvm_get_dir_entries_input,
129 				DMA_FROM_DEVICE, host_dest_addr,
130 				FWCTL_BNXT_MAX_DMABUF)),
131 	CMD_DMA_LEN(HWRM_NVM_WRITE, FWCTL_RPC_DEBUG_WRITE,
132 		    DMA_TO_DEVICE, struct hwrm_nvm_write_input,
133 		    host_src_addr, dir_data_length),
134 	CMD_DMA_LEN(HWRM_NVM_MODIFY, FWCTL_RPC_DEBUG_WRITE,
135 		    DMA_TO_DEVICE, struct hwrm_nvm_modify_input,
136 		    host_src_addr, len),
137 	CMD_DMA_LEN(HWRM_NVM_RAW_WRITE_BLK, FWCTL_RPC_DEBUG_WRITE_FULL,
138 		    DMA_TO_DEVICE,
139 		    struct hwrm_nvm_raw_write_blk_input, host_src_addr, len),
140 	CMD_DMA_LEN(HWRM_NVM_RAW_DUMP, FWCTL_RPC_DEBUG_READ_ONLY,
141 		    DMA_FROM_DEVICE, struct hwrm_nvm_raw_dump_input,
142 		    host_dest_addr, len),
143 
144 	CMD_DMA_LEN(HWRM_FW_GET_STRUCTURED_DATA, FWCTL_RPC_DEBUG_READ_ONLY,
145 		    DMA_FROM_DEVICE,
146 		    struct hwrm_fw_get_structured_data_input, dest_data_addr,
147 		    data_len),
148 	CMD_DMA_LEN(HWRM_FW_SET_STRUCTURED_DATA, FWCTL_RPC_DEBUG_WRITE,
149 		    DMA_TO_DEVICE,
150 		    struct hwrm_fw_set_structured_data_input, src_data_addr,
151 		    data_len),
152 	CMD_DMA_LEN(HWRM_FW_LIVEPATCH, FWCTL_RPC_DEBUG_WRITE_FULL,
153 		    DMA_TO_DEVICE, struct hwrm_fw_livepatch_input,
154 		    host_addr, patch_len),
155 
156 	CMD_DMA_LEN(HWRM_DBG_COREDUMP_LIST, FWCTL_RPC_DEBUG_READ_ONLY,
157 		    DMA_FROM_DEVICE,
158 		    struct hwrm_dbg_coredump_list_input, host_dest_addr,
159 		    host_buf_len),
160 	CMD_DMA_LEN(HWRM_DBG_COREDUMP_RETRIEVE, FWCTL_RPC_DEBUG_READ_ONLY,
161 		    DMA_FROM_DEVICE,
162 		    struct hwrm_dbg_coredump_retrieve_input, host_dest_addr,
163 		    host_buf_len),
164 	/* read_len32 counts 32-bit words, not bytes (see bnxt_dbg_hwrm_rd_reg()). */
165 	CMD_DMAS(HWRM_DBG_READ_DIRECT, FWCTL_RPC_DEBUG_READ_ONLY,
166 		 struct hwrm_dbg_read_direct_input, 1,
167 		 CMD_DATA_UNIT(struct hwrm_dbg_read_direct_input,
168 			       DMA_FROM_DEVICE,
169 			       host_dest_addr, read_len32, 4)),
170 	CMD_DMA_LEN(HWRM_DBG_READ_INDIRECT, FWCTL_RPC_DEBUG_READ_ONLY,
171 		    DMA_FROM_DEVICE,
172 		    struct hwrm_dbg_read_indirect_input, host_dest_addr,
173 		    host_dest_addr_len),
174 	CMD_DMA_LEN(HWRM_DBG_SERDES_TEST, FWCTL_RPC_DEBUG_READ_ONLY,
175 		    DMA_FROM_DEVICE,
176 		    struct hwrm_dbg_serdes_test_input, resp_data_addr,
177 		    data_len),
178 	CMD_DMA_LEN(HWRM_DBG_TOKEN_CFG, FWCTL_RPC_DEBUG_WRITE_FULL,
179 		    DMA_TO_DEVICE, struct hwrm_dbg_token_cfg_input,
180 		    host_src_addr, dbg_token_len),
181 
182 	CMD_DMA_LEN(HWRM_QUEUE_DSCP2PRI_QCFG, FWCTL_RPC_DEBUG_READ_ONLY,
183 		    DMA_FROM_DEVICE,
184 		    struct hwrm_queue_dscp2pri_qcfg_input, dest_data_addr,
185 		    dest_data_buffer_size),
186 
187 	CMD_DMAS(HWRM_PORT_QSTATS, FWCTL_RPC_DEBUG_READ_ONLY,
188 		 struct hwrm_port_qstats_input, 2,
189 		 CMD_DATA_FIXED(struct hwrm_port_qstats_input,
190 				DMA_FROM_DEVICE, tx_stat_host_addr,
191 				sizeof(struct tx_port_stats)),
192 		 CMD_DATA_FIXED(struct hwrm_port_qstats_input,
193 				DMA_FROM_DEVICE, rx_stat_host_addr,
194 				sizeof(struct rx_port_stats))),
195 	CMD_DMAS(HWRM_PORT_QSTATS_EXT, FWCTL_RPC_DEBUG_READ_ONLY,
196 		 struct hwrm_port_qstats_ext_input, 2,
197 		 CMD_DATA_SIMPLE(struct hwrm_port_qstats_ext_input,
198 				 DMA_FROM_DEVICE, tx_stat_host_addr,
199 				 tx_stat_size),
200 		 CMD_DATA_SIMPLE(struct hwrm_port_qstats_ext_input,
201 				 DMA_FROM_DEVICE, rx_stat_host_addr,
202 				 rx_stat_size)),
203 	CMD_DMAS(HWRM_PORT_QSTATS_EXT_PFC_ADV, FWCTL_RPC_DEBUG_READ_ONLY,
204 		 struct hwrm_port_qstats_ext_pfc_adv_input, 2,
205 		 CMD_DATA_SIMPLE(struct hwrm_port_qstats_ext_pfc_adv_input,
206 				 DMA_FROM_DEVICE,
207 				 tx_pfc_adv_stat_host_addr, pfc_adv_stat_size),
208 		 CMD_DATA_SIMPLE(struct hwrm_port_qstats_ext_pfc_adv_input,
209 				 DMA_FROM_DEVICE,
210 				 rx_pfc_adv_stat_host_addr, pfc_adv_stat_size)),
211 	CMD_DMA_LEN(HWRM_PCIE_QSTATS, FWCTL_RPC_DEBUG_READ_ONLY,
212 		    DMA_FROM_DEVICE, struct hwrm_pcie_qstats_input,
213 		    pcie_stat_host_addr, pcie_stat_size),
214 	CMD_DMA_LEN(HWRM_STAT_GENERIC_QSTATS, FWCTL_RPC_DEBUG_READ_ONLY,
215 		    DMA_FROM_DEVICE,
216 		    struct hwrm_stat_generic_qstats_input,
217 		    generic_stat_host_addr, generic_stat_size),
218 	CMD_DMA_LEN(HWRM_STAT_QUERY_ROCE_STATS, FWCTL_RPC_DEBUG_READ_ONLY,
219 		    DMA_FROM_DEVICE,
220 		    struct hwrm_stat_query_roce_stats_input,
221 		    roce_stat_host_addr, roce_stat_size),
222 	CMD_DMA_LEN(HWRM_STAT_QUERY_ROCE_STATS_EXT, FWCTL_RPC_DEBUG_READ_ONLY,
223 		    DMA_FROM_DEVICE,
224 		    struct hwrm_stat_query_roce_stats_ext_input,
225 		    roce_stat_host_addr, roce_stat_size),
226 
227 	CMD_DMA_LEN(HWRM_PORT_EVENTS_LOG, FWCTL_RPC_DEBUG_READ_ONLY,
228 		    DMA_FROM_DEVICE,
229 		    struct hwrm_port_events_log_input, host_dest_addr,
230 		    host_dest_addr_len),
231 	CMD_DMA_LEN(HWRM_PORT_PRBS_TEST, FWCTL_RPC_DEBUG_READ_ONLY,
232 		    DMA_FROM_DEVICE,
233 		    struct hwrm_port_prbs_test_input, resp_data_addr, data_len),
234 	CMD_DMA_LEN(HWRM_PORT_DSC_DUMP, FWCTL_RPC_DEBUG_READ_ONLY,
235 		    DMA_FROM_DEVICE, struct hwrm_port_dsc_dump_input,
236 		    resp_data_addr, data_len),
237 
238 	/* num_fids counts 16-bit FIDs, not bytes. */
239 	CMD_DMAS(HWRM_SCH_GRP_CFG, FWCTL_RPC_DEBUG_WRITE,
240 		 struct hwrm_sch_grp_cfg_input, 1,
241 		 CMD_DATA_UNIT(struct hwrm_sch_grp_cfg_input,
242 			       DMA_TO_DEVICE, fid_table_addr,
243 			       num_fids, 2)),
244 	CMD_DMA_LEN(HWRM_SCH_GRP_QCFG, FWCTL_RPC_DEBUG_READ_ONLY,
245 		    DMA_FROM_DEVICE, struct hwrm_sch_grp_qcfg_input,
246 		    fid_table_addr, fid_table_len),
247 
248 	CMD_DMA_LEN(HWRM_SELFTEST_RETRIEVE_SERDES_DATA,
249 		    FWCTL_RPC_DEBUG_READ_ONLY, DMA_FROM_DEVICE,
250 		    struct hwrm_selftest_retrieve_serdes_data_input,
251 		    resp_data_addr, data_len),
252 
253 	CMD_DMAS(HWRM_DBG_PTRACE, FWCTL_RPC_DEBUG_WRITE,
254 		 struct hwrm_dbg_ptrace_input, 2,
255 		 CMD_DATA_SIMPLE(struct hwrm_dbg_ptrace_input,
256 				 DMA_TO_DEVICE, pdi_cmd_buf_addr,
257 				 pdi_req_buf_len),
258 		 CMD_DATA_SIMPLE(struct hwrm_dbg_ptrace_input,
259 				 DMA_FROM_DEVICE, pdi_resp_buf_addr,
260 				 pdi_req_buf_len)),
261 };
262 
263 #undef CMD_DATA_UNIT
264 #undef CMD_DATA_SIMPLE
265 #undef CMD_DATA_FIXED
266 #undef CMD_DMAS
267 #undef CMD_DMA_LEN
268 
269 static const struct bnxtctl_cmd_dma_desc *
270 bnxtctl_find_dma_desc(u16 req_type)
271 {
272 	unsigned int i;
273 
274 	for (i = 0; i < ARRAY_SIZE(bnxtctl_dma_cmds); i++)
275 		if (bnxtctl_dma_cmds[i].req_type == req_type)
276 			return &bnxtctl_dma_cmds[i];
277 	return NULL;
278 }
279 
280 static void bnxtctl_extract_and_zero_dma_fields(void *cmd,
281 						const struct bnxtctl_cmd_dma_desc *desc,
282 						u64 *user_addrs)
283 {
284 	unsigned int i;
285 
286 	for (i = 0; i < desc->num_fields; i++) {
287 		__le32 *field = cmd + desc->fields[i].offset;
288 
289 		user_addrs[i] = le32_to_cpu(field[0]) |
290 				((u64)le32_to_cpu(field[1]) << 32);
291 		field[0] = 0;
292 		field[1] = 0;
293 	}
294 }
295 
296 static u32 bnxtctl_read_len_field(void *cmd, const struct bnxtctl_dma_field *f)
297 {
298 	if (f->len_width == 2)
299 		return le16_to_cpup((__le16 *)(cmd + f->len_offset));
300 	return le32_to_cpup((__le32 *)(cmd + f->len_offset));
301 }
302 
303 static int bnxtctl_check_dma_lens(void *cmd, const struct bnxtctl_cmd_dma_desc *desc,
304 				  u32 *lens)
305 {
306 	unsigned int i;
307 
308 	for (i = 0; i < desc->num_fields; i++) {
309 		const struct bnxtctl_dma_field *f = &desc->fields[i];
310 		u64 len;
311 
312 		if (f->len_offset) {
313 			if (check_mul_overflow(bnxtctl_read_len_field(cmd, f),
314 					       f->len_unit, &len))
315 				return -EINVAL;
316 		} else {
317 			len = f->buf_len;
318 		}
319 
320 		if (!len || len > FWCTL_BNXT_MAX_DMABUF)
321 			return -EINVAL;
322 
323 		lens[i] = len;
324 	}
325 	return 0;
326 }
327 
328 static int bnxtctl_map_dma_bufs(struct device *dev, void *cmd,
329 				const struct bnxtctl_cmd_dma_desc *desc,
330 				const u64 *user_addrs, const u32 *lens,
331 				void **kbufs, dma_addr_t *dma_addrs,
332 				unsigned int *num_mapped)
333 {
334 	unsigned int i;
335 
336 	*num_mapped = 0;
337 	for (i = 0; i < desc->num_fields; i++) {
338 		const struct bnxtctl_dma_field *f = &desc->fields[i];
339 		__le32 *field;
340 
341 		kbufs[i] = dma_alloc_coherent(dev, lens[i],
342 					      &dma_addrs[i], GFP_KERNEL);
343 		if (!kbufs[i])
344 			return -ENOMEM;
345 
346 		if (f->dir == DMA_TO_DEVICE &&
347 		    copy_from_user(kbufs[i], u64_to_user_ptr(user_addrs[i]),
348 				   lens[i])) {
349 			dma_free_coherent(dev, lens[i], kbufs[i],
350 					  dma_addrs[i]);
351 			kbufs[i] = NULL;
352 			return -EFAULT;
353 		}
354 
355 		(*num_mapped)++;
356 
357 		field = cmd + f->offset;
358 		field[0] = cpu_to_le32(lower_32_bits(dma_addrs[i]));
359 		field[1] = cpu_to_le32(upper_32_bits(dma_addrs[i]));
360 	}
361 	return 0;
362 }
363 
364 static int bnxtctl_unmap_dma_bufs(struct device *dev,
365 				  const struct bnxtctl_cmd_dma_desc *desc,
366 				  const u64 *user_addrs, const u32 *lens,
367 				  void **kbufs, dma_addr_t *dma_addrs,
368 				  unsigned int num_mapped)
369 {
370 	unsigned int i;
371 	int rc = 0;
372 
373 	for (i = 0; i < num_mapped; i++) {
374 		if (desc->fields[i].dir == DMA_FROM_DEVICE &&
375 		    copy_to_user(u64_to_user_ptr(user_addrs[i]),
376 				 kbufs[i], lens[i]))
377 			rc = -EFAULT;
378 
379 		dma_free_coherent(dev, lens[i], kbufs[i], dma_addrs[i]);
380 	}
381 	return rc;
382 }
383 
384 /* Caller must hold edev->en_dev_lock */
385 static bool bnxtctl_validate_rpc(struct bnxt_en_dev *edev,
386 				 struct bnxt_fw_msg *hwrm_in,
387 				 enum fwctl_rpc_scope scope)
388 {
389 	struct input *req = (struct input *)hwrm_in->msg;
390 	u16 req_type = le16_to_cpu(req->req_type);
391 	const struct bnxtctl_cmd_dma_desc *desc;
392 
393 	lockdep_assert_held(&edev->en_dev_lock);
394 	if (edev->flags & BNXT_EN_FLAG_ULP_STOPPED)
395 		return false;
396 
397 	desc = bnxtctl_find_dma_desc(req_type);
398 	if (desc)
399 		return scope >= desc->scope_min;
400 
401 	switch (req_type) {
402 	case HWRM_FUNC_RESET:
403 	case HWRM_PORT_CLR_STATS:
404 	case HWRM_FW_RESET:
405 	case HWRM_FW_SYNC:
406 	case HWRM_FW_SET_TIME:
407 	case HWRM_DBG_LOG_BUFFER_FLUSH:
408 	case HWRM_DBG_ERASE_NVM:
409 	case HWRM_DBG_CFG:
410 	case HWRM_NVM_DEFRAG:
411 	case HWRM_NVM_FACTORY_DEFAULTS:
412 	case HWRM_NVM_FLUSH:
413 	case HWRM_NVM_VERIFY_UPDATE:
414 	case HWRM_NVM_ERASE_DIR_ENTRY:
415 	case HWRM_NVM_MOD_DIR_ENTRY:
416 	case HWRM_NVM_FIND_DIR_ENTRY:
417 		return scope >= FWCTL_RPC_CONFIGURATION;
418 
419 	case HWRM_VER_GET:
420 	case HWRM_ERROR_RECOVERY_QCFG:
421 	case HWRM_FUNC_QCAPS:
422 	case HWRM_FUNC_QCFG:
423 	case HWRM_FUNC_QSTATS:
424 	case HWRM_PORT_PHY_QCFG:
425 	case HWRM_PORT_MAC_QCFG:
426 	case HWRM_PORT_PHY_QCAPS:
427 	case HWRM_PORT_PHY_I2C_READ:
428 	case HWRM_PORT_PHY_MDIO_READ:
429 	case HWRM_QUEUE_PRI2COS_QCFG:
430 	case HWRM_QUEUE_COS2BW_QCFG:
431 	case HWRM_VNIC_RSS_QCFG:
432 	case HWRM_QUEUE_GLOBAL_QCFG:
433 	case HWRM_QUEUE_ADPTV_QOS_RX_FEATURE_QCFG:
434 	case HWRM_QUEUE_ADPTV_QOS_TX_FEATURE_QCFG:
435 	case HWRM_QUEUE_QCAPS:
436 	case HWRM_QUEUE_ADPTV_QOS_RX_TUNING_QCFG:
437 	case HWRM_QUEUE_ADPTV_QOS_TX_TUNING_QCFG:
438 	case HWRM_TUNNEL_DST_PORT_QUERY:
439 	case HWRM_PORT_TX_FIR_QCFG:
440 	case HWRM_FW_LIVEPATCH_QUERY:
441 	case HWRM_FW_QSTATUS:
442 	case HWRM_FW_HEALTH_CHECK:
443 	case HWRM_FW_GET_TIME:
444 	case HWRM_PORT_EP_TX_QCFG:
445 	case HWRM_PORT_QCFG:
446 	case HWRM_PORT_MAC_QCAPS:
447 	case HWRM_TEMP_MONITOR_QUERY:
448 	case HWRM_REG_POWER_QUERY:
449 	case HWRM_CORE_FREQUENCY_QUERY:
450 	case HWRM_CFA_REDIRECT_QUERY_TUNNEL_TYPE:
451 	case HWRM_CFA_ADV_FLOW_MGNT_QCAPS:
452 	case HWRM_FUNC_RESOURCE_QCAPS:
453 	case HWRM_FUNC_BACKING_STORE_QCAPS:
454 	case HWRM_FUNC_BACKING_STORE_QCFG:
455 	case HWRM_FUNC_QSTATS_EXT:
456 	case HWRM_FUNC_PTP_PIN_QCFG:
457 	case HWRM_FUNC_PTP_EXT_QCFG:
458 	case HWRM_FUNC_BACKING_STORE_QCFG_V2:
459 	case HWRM_FUNC_BACKING_STORE_QCAPS_V2:
460 	case HWRM_FUNC_SYNCE_QCFG:
461 	case HWRM_FUNC_TTX_PACING_RATE_PROF_QUERY:
462 	case HWRM_PORT_PHY_FDRSTAT:
463 	case HWRM_DBG_RING_INFO_GET:
464 	case HWRM_DBG_QCAPS:
465 	case HWRM_DBG_QCFG:
466 	case HWRM_DBG_USEQ_FLUSH:
467 	case HWRM_DBG_USEQ_QCAPS:
468 	case HWRM_DBG_SIM_CABLE_STATE:
469 	case HWRM_DBG_TOKEN_QUERY_AUTH_IDS:
470 	case HWRM_NVM_GET_DEV_INFO:
471 	case HWRM_NVM_GET_DIR_INFO:
472 	case HWRM_SELFTEST_QLIST:
473 	case HWRM_DBG_COREDUMP_INITIATE:
474 		return scope >= FWCTL_RPC_DEBUG_READ_ONLY;
475 
476 	case HWRM_PORT_PHY_I2C_WRITE:
477 	case HWRM_PORT_PHY_MDIO_WRITE:
478 		return scope >= FWCTL_RPC_DEBUG_WRITE;
479 
480 	default:
481 		return false;
482 	}
483 }
484 
485 #define BNXTCTL_HWRM_CMD_TIMEOUT_DFLT	500	/* ms */
486 #define BNXTCTL_HWRM_CMD_TIMEOUT_MEDM	2000	/* ms */
487 #define BNXTCTL_HWRM_CMD_TIMEOUT_LONG	60000	/* ms */
488 
489 static unsigned int bnxtctl_get_timeout(struct input *req)
490 {
491 	switch (le16_to_cpu(req->req_type)) {
492 	case HWRM_NVM_DEFRAG:
493 	case HWRM_NVM_FACTORY_DEFAULTS:
494 	case HWRM_NVM_FLUSH:
495 	case HWRM_NVM_VERIFY_UPDATE:
496 	case HWRM_NVM_ERASE_DIR_ENTRY:
497 	case HWRM_NVM_MOD_DIR_ENTRY:
498 	case HWRM_NVM_WRITE:
499 	case HWRM_FW_SYNC:
500 	case HWRM_DBG_COREDUMP_LIST:
501 	case HWRM_DBG_COREDUMP_RETRIEVE:
502 	case HWRM_DBG_COREDUMP_INITIATE:
503 	case HWRM_SELFTEST_RETRIEVE_SERDES_DATA:
504 	case HWRM_DBG_SERDES_TEST:
505 	case HWRM_NVM_RAW_WRITE_BLK:
506 	case HWRM_FW_HEALTH_CHECK:
507 		return BNXTCTL_HWRM_CMD_TIMEOUT_LONG;
508 	case HWRM_FUNC_RESET:
509 		return BNXTCTL_HWRM_CMD_TIMEOUT_MEDM;
510 	default:
511 		return BNXTCTL_HWRM_CMD_TIMEOUT_DFLT;
512 	}
513 }
514 
515 static void *bnxtctl_fw_rpc(struct fwctl_uctx *uctx,
516 			    enum fwctl_rpc_scope scope,
517 			    void *in, size_t in_len, size_t *out_len)
518 {
519 	struct bnxtctl_dev *bnxtctl =
520 		container_of(uctx->fwctl, struct bnxtctl_dev, fwctl);
521 	struct bnxt_en_dev *edev = bnxtctl->aux_priv->edev;
522 	dma_addr_t dma_addrs[BNXTCTL_MAX_DMA_FIELDS];
523 	void *kbufs[BNXTCTL_MAX_DMA_FIELDS] = {};
524 	const struct bnxtctl_cmd_dma_desc *desc;
525 	u64 user_addrs[BNXTCTL_MAX_DMA_FIELDS];
526 	struct device *dev = &edev->pdev->dev;
527 	u32 dma_lens[BNXTCTL_MAX_DMA_FIELDS];
528 	struct bnxt_fw_msg rpc_in = {};
529 	unsigned int num_mapped = 0;
530 	struct input *req = in;
531 	int rc;
532 
533 	if (in_len < sizeof(struct input) || in_len > HWRM_MAX_REQ_LEN)
534 		return ERR_PTR(-EINVAL);
535 
536 	if (*out_len < sizeof(struct output))
537 		return ERR_PTR(-EINVAL);
538 
539 	desc = bnxtctl_find_dma_desc(le16_to_cpu(req->req_type));
540 
541 	if (desc) {
542 		if (in_len != desc->req_size)
543 			return ERR_PTR(-EINVAL);
544 
545 		rc = bnxtctl_check_dma_lens(in, desc, dma_lens);
546 		if (rc)
547 			return ERR_PTR(rc);
548 
549 		bnxtctl_extract_and_zero_dma_fields(in, desc, user_addrs);
550 	}
551 
552 	rpc_in.msg = in;
553 	rpc_in.msg_len = in_len;
554 	rpc_in.resp = kvzalloc(*out_len, GFP_KERNEL);
555 	if (!rpc_in.resp)
556 		return ERR_PTR(-ENOMEM);
557 
558 	rpc_in.resp_max_len = *out_len;
559 	rpc_in.timeout = bnxtctl_get_timeout(in);
560 
561 	guard(mutex)(&edev->en_dev_lock);
562 
563 	if (!bnxtctl_validate_rpc(edev, &rpc_in, scope)) {
564 		kvfree(rpc_in.resp);
565 		return ERR_PTR(-EPERM);
566 	}
567 
568 	if (desc) {
569 		rc = bnxtctl_map_dma_bufs(dev, in, desc, user_addrs, dma_lens,
570 					  kbufs, dma_addrs, &num_mapped);
571 		if (rc) {
572 			bnxtctl_unmap_dma_bufs(dev, desc, user_addrs, dma_lens,
573 					       kbufs, dma_addrs, num_mapped);
574 			kvfree(rpc_in.resp);
575 			return ERR_PTR(rc);
576 		}
577 	}
578 
579 	rc = bnxt_send_msg(edev, &rpc_in);
580 	if (rc) {
581 		struct output *resp = rpc_in.resp;
582 
583 		/* Copy the response to user always, as it contains
584 		 * detailed status of the command failure
585 		 */
586 		if (!resp->error_code)
587 			/* bnxt_send_msg() returned much before FW
588 			 * received the command.
589 			 */
590 			resp->error_code = cpu_to_le16(rc);
591 	}
592 
593 	if (desc) {
594 		int unmap_rc;
595 
596 		unmap_rc = bnxtctl_unmap_dma_bufs(dev, desc, user_addrs,
597 						  dma_lens, kbufs, dma_addrs,
598 						  num_mapped);
599 		if (unmap_rc) {
600 			kvfree(rpc_in.resp);
601 			return ERR_PTR(unmap_rc);
602 		}
603 	}
604 
605 	return rpc_in.resp;
606 }
607 
608 static const struct fwctl_ops bnxtctl_ops = {
609 	.device_type = FWCTL_DEVICE_TYPE_BNXT,
610 	.uctx_size = sizeof(struct bnxtctl_uctx),
611 	.open_uctx = bnxtctl_open_uctx,
612 	.close_uctx = bnxtctl_close_uctx,
613 	.info = bnxtctl_info,
614 	.fw_rpc = bnxtctl_fw_rpc,
615 };
616 
617 static int bnxtctl_probe(struct auxiliary_device *adev,
618 			 const struct auxiliary_device_id *id)
619 {
620 	struct bnxt_aux_priv *aux_priv =
621 		container_of(adev, struct bnxt_aux_priv, aux_dev);
622 	struct bnxtctl_dev *bnxtctl __free(bnxtctl) =
623 		fwctl_alloc_device(&aux_priv->edev->pdev->dev, &bnxtctl_ops,
624 				   struct bnxtctl_dev, fwctl);
625 	int rc;
626 
627 	if (!bnxtctl)
628 		return -ENOMEM;
629 
630 	bnxtctl->aux_priv = aux_priv;
631 
632 	rc = fwctl_register(&bnxtctl->fwctl);
633 	if (rc)
634 		return rc;
635 
636 	auxiliary_set_drvdata(adev, no_free_ptr(bnxtctl));
637 	return 0;
638 }
639 
640 static void bnxtctl_remove(struct auxiliary_device *adev)
641 {
642 	struct bnxtctl_dev *ctldev = auxiliary_get_drvdata(adev);
643 
644 	fwctl_unregister(&ctldev->fwctl);
645 	fwctl_put(&ctldev->fwctl);
646 }
647 
648 static const struct auxiliary_device_id bnxtctl_id_table[] = {
649 	{ .name = "bnxt_en.fwctl", },
650 	{}
651 };
652 MODULE_DEVICE_TABLE(auxiliary, bnxtctl_id_table);
653 
654 static struct auxiliary_driver bnxtctl_driver = {
655 	.name = "bnxt_fwctl",
656 	.probe = bnxtctl_probe,
657 	.remove = bnxtctl_remove,
658 	.id_table = bnxtctl_id_table,
659 };
660 
661 module_auxiliary_driver(bnxtctl_driver);
662 
663 MODULE_IMPORT_NS("FWCTL");
664 MODULE_DESCRIPTION("BNXT fwctl driver");
665 MODULE_AUTHOR("Pavan Chebbi <pavan.chebbi@broadcom.com>");
666 MODULE_AUTHOR("Andy Gospodarek <gospo@broadcom.com>");
667 MODULE_LICENSE("GPL");
668