// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2025 Intel Corporation */ #include "ixd.h" #include "ixd_ctlq.h" #include "ixd_devlink.h" #include "ixd_virtchnl.h" #define IXD_DFLT_MBX_Q_LEN 64 /** * ixd_init_ctlq_create_info - Initialize control queue info for creation * @info: destination * @type: type of the queue to create * @ctlq_reg: register assigned to the control queue */ static void ixd_init_ctlq_create_info(struct libie_ctlq_create_info *info, enum libie_ctlq_type type, const struct libie_ctlq_reg *ctlq_reg) { *info = (struct libie_ctlq_create_info) { .type = type, .id = -1, .reg = *ctlq_reg, .len = IXD_DFLT_MBX_Q_LEN, }; } /** * ixd_init_libie_xn_params - Initialize xn transaction manager creation info * @params: destination * @adapter: adapter info struct * @ctlqs: list of the managed queues to create * @num_queues: length of the queue list */ static void ixd_init_libie_xn_params(struct libie_ctlq_xn_init_params *params, struct ixd_adapter *adapter, struct libie_ctlq_create_info *ctlqs, uint num_queues) { *params = (struct libie_ctlq_xn_init_params){ .cctlq_info = ctlqs, .ctx = &adapter->cp_ctx, .num_qs = num_queues, }; } /** * ixd_adapter_fill_dflt_ctlqs - Find default control queues and store them * @adapter: adapter info struct */ static void ixd_adapter_fill_dflt_ctlqs(struct ixd_adapter *adapter) { adapter->arq = libie_find_ctlq(&adapter->cp_ctx, LIBIE_CTLQ_TYPE_RX, LIBIE_CTLQ_MBX_ID); adapter->asq = libie_find_ctlq(&adapter->cp_ctx, LIBIE_CTLQ_TYPE_TX, LIBIE_CTLQ_MBX_ID); } /** * ixd_deinit_dflt_mbx - Deinitialize default mailbox * @adapter: adapter info struct */ void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter) { cancel_delayed_work_sync(&adapter->mbx_task); if (adapter->xnm) libie_ctlq_xn_shutdown(adapter->xnm); if (adapter->asq) ixd_ctlq_clean_sq(adapter, true); if (adapter->xnm) libie_ctlq_xn_deinit(adapter->xnm, &adapter->cp_ctx); adapter->arq = NULL; adapter->asq = NULL; adapter->xnm = NULL; } /** * ixd_init_dflt_mbx - Setup default mailbox parameters and make request * @adapter: adapter info struct * * Return: %0 on success, negative errno code on failure */ int ixd_init_dflt_mbx(struct ixd_adapter *adapter) { struct libie_ctlq_create_info ctlqs_info[2]; struct libie_ctlq_xn_init_params xn_params; struct libie_ctlq_reg ctlq_reg_tx; struct libie_ctlq_reg ctlq_reg_rx; int err; ixd_ctlq_reg_init(adapter, &ctlq_reg_tx, &ctlq_reg_rx); ixd_init_ctlq_create_info(&ctlqs_info[0], LIBIE_CTLQ_TYPE_TX, &ctlq_reg_tx); ixd_init_ctlq_create_info(&ctlqs_info[1], LIBIE_CTLQ_TYPE_RX, &ctlq_reg_rx); ixd_init_libie_xn_params(&xn_params, adapter, ctlqs_info, ARRAY_SIZE(ctlqs_info)); err = libie_ctlq_xn_init(&xn_params); if (err) return err; adapter->xnm = xn_params.xnm; ixd_adapter_fill_dflt_ctlqs(adapter); if (!adapter->asq || !adapter->arq) { ixd_deinit_dflt_mbx(adapter); return -ENOENT; } queue_delayed_work(system_dfl_wq, &adapter->mbx_task, 0); return 0; } /** * ixd_init_task - Initialize after reset * @work: init work struct */ void ixd_init_task(struct work_struct *work) { struct ixd_adapter *adapter; int err; adapter = container_of(work, struct ixd_adapter, init_task.init_work.work); if (!ixd_check_reset_complete(adapter)) { if (++adapter->init_task.reset_retries < 10) queue_delayed_work(system_dfl_wq, &adapter->init_task.init_work, IXD_INIT_TASK_DELAY_JIFFIES); else dev_err(ixd_to_dev(adapter), "Device reset failed. The driver was unable to contact the device's firmware. Check that the FW is running.\n"); return; } adapter->init_task.reset_retries = 0; err = ixd_init_dflt_mbx(adapter); if (err) { dev_err(ixd_to_dev(adapter), "Failed to initialize the default mailbox: %pe\n", ERR_PTR(err)); return; } err = ixd_vc_dev_init(adapter); if (!err) { adapter->init_task.vc_retries = 0; adapter->init_task.success = true; ixd_devlink_register(adapter); return; } libie_ctlq_xn_shutdown(adapter->xnm); ixd_trigger_reset(adapter); ixd_deinit_dflt_mbx(adapter); if (++adapter->init_task.vc_retries > 5 || (err != -ETIMEDOUT && err != -EAGAIN && err != -EBUSY)) { dev_err(ixd_to_dev(adapter), "Failed to establish mailbox communication with the hardware: %pe\n", ERR_PTR(err)); return; } queue_delayed_work(system_dfl_wq, &adapter->init_task.init_work, IXD_INIT_TASK_DELAY_JIFFIES); }