// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2023 Intel Corporation */ #include <net/libeth/rx.h> #include "idpf.h" #include "idpf_virtchnl.h" #define IDPF_VC_XN_MIN_TIMEOUT_MSEC … #define IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC … #define IDPF_VC_XN_IDX_M … #define IDPF_VC_XN_SALT_M … #define IDPF_VC_XN_RING_LEN … /** * enum idpf_vc_xn_state - Virtchnl transaction status * @IDPF_VC_XN_IDLE: not expecting a reply, ready to be used * @IDPF_VC_XN_WAITING: expecting a reply, not yet received * @IDPF_VC_XN_COMPLETED_SUCCESS: a reply was expected and received, * buffer updated * @IDPF_VC_XN_COMPLETED_FAILED: a reply was expected and received, but there * was an error, buffer not updated * @IDPF_VC_XN_SHUTDOWN: transaction object cannot be used, VC torn down * @IDPF_VC_XN_ASYNC: transaction sent asynchronously and doesn't have the * return context; a callback may be provided to handle * return */ enum idpf_vc_xn_state { … }; struct idpf_vc_xn; /* Callback for asynchronous messages */ async_vc_cb; /** * struct idpf_vc_xn - Data structure representing virtchnl transactions * @completed: virtchnl event loop uses that to signal when a reply is * available, uses kernel completion API * @state: virtchnl event loop stores the data below, protected by the * completion's lock. * @reply_sz: Original size of reply, may be > reply_buf.iov_len; it will be * truncated on its way to the receiver thread according to * reply_buf.iov_len. * @reply: Reference to the buffer(s) where the reply data should be written * to. May be 0-length (then NULL address permitted) if the reply data * should be ignored. * @async_handler: if sent asynchronously, a callback can be provided to handle * the reply when it's received * @vc_op: corresponding opcode sent with this transaction * @idx: index used as retrieval on reply receive, used for cookie * @salt: changed every message to make unique, used for cookie */ struct idpf_vc_xn { … }; /** * struct idpf_vc_xn_params - Parameters for executing transaction * @send_buf: kvec for send buffer * @recv_buf: kvec for recv buffer, may be NULL, must then have zero length * @timeout_ms: timeout to wait for reply * @async: send message asynchronously, will not wait on completion * @async_handler: If sent asynchronously, optional callback handler. The user * must be careful when using async handlers as the memory for * the recv_buf _cannot_ be on stack if this is async. * @vc_op: virtchnl op to send */ struct idpf_vc_xn_params { … }; /** * struct idpf_vc_xn_manager - Manager for tracking transactions * @ring: backing and lookup for transactions * @free_xn_bm: bitmap for free transactions * @xn_bm_lock: make bitmap access synchronous where necessary * @salt: used to make cookie unique every message */ struct idpf_vc_xn_manager { … }; /** * idpf_vid_to_vport - Translate vport id to vport pointer * @adapter: private data struct * @v_id: vport id to translate * * Returns vport matching v_id, NULL if not found. */ static struct idpf_vport *idpf_vid_to_vport(struct idpf_adapter *adapter, u32 v_id) { … } /** * idpf_handle_event_link - Handle link event message * @adapter: private data struct * @v2e: virtchnl event message */ static void idpf_handle_event_link(struct idpf_adapter *adapter, const struct virtchnl2_event *v2e) { … } /** * idpf_recv_event_msg - Receive virtchnl event message * @adapter: Driver specific private structure * @ctlq_msg: message to copy from * * Receive virtchnl event message */ static void idpf_recv_event_msg(struct idpf_adapter *adapter, struct idpf_ctlq_msg *ctlq_msg) { … } /** * idpf_mb_clean - Reclaim the send mailbox queue entries * @adapter: Driver specific private structure * * Reclaim the send mailbox queue entries to be used to send further messages * * Returns 0 on success, negative on failure */ static int idpf_mb_clean(struct idpf_adapter *adapter) { … } /** * idpf_send_mb_msg - Send message over mailbox * @adapter: Driver specific private structure * @op: virtchnl opcode * @msg_size: size of the payload * @msg: pointer to buffer holding the payload * @cookie: unique SW generated cookie per message * * Will prepare the control queue message and initiates the send api * * Returns 0 on success, negative on failure */ int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op, u16 msg_size, u8 *msg, u16 cookie) { … } /* API for virtchnl "transaction" support ("xn" for short). * * We are reusing the completion lock to serialize the accesses to the * transaction state for simplicity, but it could be its own separate synchro * as well. For now, this API is only used from within a workqueue context; * raw_spin_lock() is enough. */ /** * idpf_vc_xn_lock - Request exclusive access to vc transaction * @xn: struct idpf_vc_xn* to access */ #define idpf_vc_xn_lock(xn) … /** * idpf_vc_xn_unlock - Release exclusive access to vc transaction * @xn: struct idpf_vc_xn* to access */ #define idpf_vc_xn_unlock(xn) … /** * idpf_vc_xn_release_bufs - Release reference to reply buffer(s) and * reset the transaction state. * @xn: struct idpf_vc_xn to update */ static void idpf_vc_xn_release_bufs(struct idpf_vc_xn *xn) { … } /** * idpf_vc_xn_init - Initialize virtchnl transaction object * @vcxn_mngr: pointer to vc transaction manager struct */ static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr) { … } /** * idpf_vc_xn_shutdown - Uninitialize virtchnl transaction object * @vcxn_mngr: pointer to vc transaction manager struct * * All waiting threads will be woken-up and their transaction aborted. Further * operations on that object will fail. */ static void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr) { … } /** * idpf_vc_xn_pop_free - Pop a free transaction from free list * @vcxn_mngr: transaction manager to pop from * * Returns NULL if no free transactions */ static struct idpf_vc_xn *idpf_vc_xn_pop_free(struct idpf_vc_xn_manager *vcxn_mngr) { … } /** * idpf_vc_xn_push_free - Push a free transaction to free list * @vcxn_mngr: transaction manager to push to * @xn: transaction to push */ static void idpf_vc_xn_push_free(struct idpf_vc_xn_manager *vcxn_mngr, struct idpf_vc_xn *xn) { … } /** * idpf_vc_xn_exec - Perform a send/recv virtchnl transaction * @adapter: driver specific private structure with vcxn_mngr * @params: parameters for this particular transaction including * -vc_op: virtchannel operation to send * -send_buf: kvec iov for send buf and len * -recv_buf: kvec iov for recv buf and len (ignored if NULL) * -timeout_ms: timeout waiting for a reply (milliseconds) * -async: don't wait for message reply, will lose caller context * -async_handler: callback to handle async replies * * @returns >= 0 for success, the size of the initial reply (may or may not be * >= @recv_buf.iov_len, but we never overflow @@recv_buf_iov_base). < 0 for * error. */ static ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter, const struct idpf_vc_xn_params *params) { … } /** * idpf_vc_xn_forward_async - Handle async reply receives * @adapter: private data struct * @xn: transaction to handle * @ctlq_msg: corresponding ctlq_msg * * For async sends we're going to lose the caller's context so, if an * async_handler was provided, it can deal with the reply, otherwise we'll just * check and report if there is an error. */ static int idpf_vc_xn_forward_async(struct idpf_adapter *adapter, struct idpf_vc_xn *xn, const struct idpf_ctlq_msg *ctlq_msg) { … } /** * idpf_vc_xn_forward_reply - copy a reply back to receiving thread * @adapter: driver specific private structure with vcxn_mngr * @ctlq_msg: controlq message to send back to receiving thread */ static int idpf_vc_xn_forward_reply(struct idpf_adapter *adapter, const struct idpf_ctlq_msg *ctlq_msg) { … } /** * idpf_recv_mb_msg - Receive message over mailbox * @adapter: Driver specific private structure * * Will receive control queue message and posts the receive buffer. Returns 0 * on success and negative on failure. */ int idpf_recv_mb_msg(struct idpf_adapter *adapter) { … } /** * idpf_wait_for_marker_event - wait for software marker response * @vport: virtual port data structure * * Returns 0 success, negative on failure. **/ static int idpf_wait_for_marker_event(struct idpf_vport *vport) { … } /** * idpf_send_ver_msg - send virtchnl version message * @adapter: Driver specific private structure * * Send virtchnl version message. Returns 0 on success, negative on failure. */ static int idpf_send_ver_msg(struct idpf_adapter *adapter) { … } /** * idpf_send_get_caps_msg - Send virtchnl get capabilities message * @adapter: Driver specific private structure * * Send virtchl get capabilities message. Returns 0 on success, negative on * failure. */ static int idpf_send_get_caps_msg(struct idpf_adapter *adapter) { … } /** * idpf_vport_alloc_max_qs - Allocate max queues for a vport * @adapter: Driver specific private structure * @max_q: vport max queue structure */ int idpf_vport_alloc_max_qs(struct idpf_adapter *adapter, struct idpf_vport_max_q *max_q) { … } /** * idpf_vport_dealloc_max_qs - Deallocate max queues of a vport * @adapter: Driver specific private structure * @max_q: vport max queue structure */ void idpf_vport_dealloc_max_qs(struct idpf_adapter *adapter, struct idpf_vport_max_q *max_q) { … } /** * idpf_init_avail_queues - Initialize available queues on the device * @adapter: Driver specific private structure */ static void idpf_init_avail_queues(struct idpf_adapter *adapter) { … } /** * idpf_get_reg_intr_vecs - Get vector queue register offset * @vport: virtual port structure * @reg_vals: Register offsets to store in * * Returns number of registers that got populated */ int idpf_get_reg_intr_vecs(struct idpf_vport *vport, struct idpf_vec_regs *reg_vals) { … } /** * idpf_vport_get_q_reg - Get the queue registers for the vport * @reg_vals: register values needing to be set * @num_regs: amount we expect to fill * @q_type: queue model * @chunks: queue regs received over mailbox * * This function parses the queue register offsets from the queue register * chunk information, with a specific queue type and stores it into the array * passed as an argument. It returns the actual number of queue registers that * are filled. */ static int idpf_vport_get_q_reg(u32 *reg_vals, int num_regs, u32 q_type, struct virtchnl2_queue_reg_chunks *chunks) { … } /** * __idpf_queue_reg_init - initialize queue registers * @vport: virtual port structure * @reg_vals: registers we are initializing * @num_regs: how many registers there are in total * @q_type: queue model * * Return number of queues that are initialized */ static int __idpf_queue_reg_init(struct idpf_vport *vport, u32 *reg_vals, int num_regs, u32 q_type) { … } /** * idpf_queue_reg_init - initialize queue registers * @vport: virtual port structure * * Return 0 on success, negative on failure */ int idpf_queue_reg_init(struct idpf_vport *vport) { … } /** * idpf_send_create_vport_msg - Send virtchnl create vport message * @adapter: Driver specific private structure * @max_q: vport max queue info * * send virtchnl creae vport message * * Returns 0 on success, negative on failure */ int idpf_send_create_vport_msg(struct idpf_adapter *adapter, struct idpf_vport_max_q *max_q) { … } /** * idpf_check_supported_desc_ids - Verify we have required descriptor support * @vport: virtual port structure * * Return 0 on success, error on failure */ int idpf_check_supported_desc_ids(struct idpf_vport *vport) { … } /** * idpf_send_destroy_vport_msg - Send virtchnl destroy vport message * @vport: virtual port data structure * * Send virtchnl destroy vport message. Returns 0 on success, negative on * failure. */ int idpf_send_destroy_vport_msg(struct idpf_vport *vport) { … } /** * idpf_send_enable_vport_msg - Send virtchnl enable vport message * @vport: virtual port data structure * * Send enable vport virtchnl message. Returns 0 on success, negative on * failure. */ int idpf_send_enable_vport_msg(struct idpf_vport *vport) { … } /** * idpf_send_disable_vport_msg - Send virtchnl disable vport message * @vport: virtual port data structure * * Send disable vport virtchnl message. Returns 0 on success, negative on * failure. */ int idpf_send_disable_vport_msg(struct idpf_vport *vport) { … } /** * idpf_send_config_tx_queues_msg - Send virtchnl config tx queues message * @vport: virtual port data structure * * Send config tx queues virtchnl message. Returns 0 on success, negative on * failure. */ static int idpf_send_config_tx_queues_msg(struct idpf_vport *vport) { … } /** * idpf_send_config_rx_queues_msg - Send virtchnl config rx queues message * @vport: virtual port data structure * * Send config rx queues virtchnl message. Returns 0 on success, negative on * failure. */ static int idpf_send_config_rx_queues_msg(struct idpf_vport *vport) { … } /** * idpf_send_ena_dis_queues_msg - Send virtchnl enable or disable * queues message * @vport: virtual port data structure * @ena: if true enable, false disable * * Send enable or disable queues virtchnl message. Returns 0 on success, * negative on failure. */ static int idpf_send_ena_dis_queues_msg(struct idpf_vport *vport, bool ena) { … } /** * idpf_send_map_unmap_queue_vector_msg - Send virtchnl map or unmap queue * vector message * @vport: virtual port data structure * @map: true for map and false for unmap * * Send map or unmap queue vector virtchnl message. Returns 0 on success, * negative on failure. */ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map) { … } /** * idpf_send_enable_queues_msg - send enable queues virtchnl message * @vport: Virtual port private data structure * * Will send enable queues virtchnl message. Returns 0 on success, negative on * failure. */ int idpf_send_enable_queues_msg(struct idpf_vport *vport) { … } /** * idpf_send_disable_queues_msg - send disable queues virtchnl message * @vport: Virtual port private data structure * * Will send disable queues virtchnl message. Returns 0 on success, negative * on failure. */ int idpf_send_disable_queues_msg(struct idpf_vport *vport) { … } /** * idpf_convert_reg_to_queue_chunks - Copy queue chunk information to the right * structure * @dchunks: Destination chunks to store data to * @schunks: Source chunks to copy data from * @num_chunks: number of chunks to copy */ static void idpf_convert_reg_to_queue_chunks(struct virtchnl2_queue_chunk *dchunks, struct virtchnl2_queue_reg_chunk *schunks, u16 num_chunks) { … } /** * idpf_send_delete_queues_msg - send delete queues virtchnl message * @vport: Virtual port private data structure * * Will send delete queues virtchnl message. Return 0 on success, negative on * failure. */ int idpf_send_delete_queues_msg(struct idpf_vport *vport) { … } /** * idpf_send_config_queues_msg - Send config queues virtchnl message * @vport: Virtual port private data structure * * Will send config queues virtchnl message. Returns 0 on success, negative on * failure. */ int idpf_send_config_queues_msg(struct idpf_vport *vport) { … } /** * idpf_send_add_queues_msg - Send virtchnl add queues message * @vport: Virtual port private data structure * @num_tx_q: number of transmit queues * @num_complq: number of transmit completion queues * @num_rx_q: number of receive queues * @num_rx_bufq: number of receive buffer queues * * Returns 0 on success, negative on failure. vport _MUST_ be const here as * we should not change any fields within vport itself in this function. */ int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q, u16 num_complq, u16 num_rx_q, u16 num_rx_bufq) { … } /** * idpf_send_alloc_vectors_msg - Send virtchnl alloc vectors message * @adapter: Driver specific private structure * @num_vectors: number of vectors to be allocated * * Returns 0 on success, negative on failure. */ int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors) { … } /** * idpf_send_dealloc_vectors_msg - Send virtchnl de allocate vectors message * @adapter: Driver specific private structure * * Returns 0 on success, negative on failure. */ int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter) { … } /** * idpf_get_max_vfs - Get max number of vfs supported * @adapter: Driver specific private structure * * Returns max number of VFs */ static int idpf_get_max_vfs(struct idpf_adapter *adapter) { … } /** * idpf_send_set_sriov_vfs_msg - Send virtchnl set sriov vfs message * @adapter: Driver specific private structure * @num_vfs: number of virtual functions to be created * * Returns 0 on success, negative on failure. */ int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs) { … } /** * idpf_send_get_stats_msg - Send virtchnl get statistics message * @vport: vport to get stats for * * Returns 0 on success, negative on failure. */ int idpf_send_get_stats_msg(struct idpf_vport *vport) { … } /** * idpf_send_get_set_rss_lut_msg - Send virtchnl get or set rss lut message * @vport: virtual port data structure * @get: flag to set or get rss look up table * * Returns 0 on success, negative on failure. */ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get) { … } /** * idpf_send_get_set_rss_key_msg - Send virtchnl get or set rss key message * @vport: virtual port data structure * @get: flag to set or get rss look up table * * Returns 0 on success, negative on failure */ int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get) { … } /** * idpf_fill_ptype_lookup - Fill L3 specific fields in ptype lookup table * @ptype: ptype lookup table * @pstate: state machine for ptype lookup table * @ipv4: ipv4 or ipv6 * @frag: fragmentation allowed * */ static void idpf_fill_ptype_lookup(struct libeth_rx_pt *ptype, struct idpf_ptype_state *pstate, bool ipv4, bool frag) { … } static void idpf_finalize_ptype_lookup(struct libeth_rx_pt *ptype) { … } /** * idpf_send_get_rx_ptype_msg - Send virtchnl for ptype info * @vport: virtual port data structure * * Returns 0 on success, negative on failure. */ int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport) { … } /** * idpf_send_ena_dis_loopback_msg - Send virtchnl enable/disable loopback * message * @vport: virtual port data structure * * Returns 0 on success, negative on failure. */ int idpf_send_ena_dis_loopback_msg(struct idpf_vport *vport) { … } /** * idpf_find_ctlq - Given a type and id, find ctlq info * @hw: hardware struct * @type: type of ctrlq to find * @id: ctlq id to find * * Returns pointer to found ctlq info struct, NULL otherwise. */ static struct idpf_ctlq_info *idpf_find_ctlq(struct idpf_hw *hw, enum idpf_ctlq_type type, int id) { … } /** * idpf_init_dflt_mbx - Setup default mailbox parameters and make request * @adapter: adapter info struct * * Returns 0 on success, negative otherwise */ int idpf_init_dflt_mbx(struct idpf_adapter *adapter) { … } /** * idpf_deinit_dflt_mbx - Free up ctlqs setup * @adapter: Driver specific private data structure */ void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter) { … } /** * idpf_vport_params_buf_rel - Release memory for MailBox resources * @adapter: Driver specific private data structure * * Will release memory to hold the vport parameters received on MailBox */ static void idpf_vport_params_buf_rel(struct idpf_adapter *adapter) { … } /** * idpf_vport_params_buf_alloc - Allocate memory for MailBox resources * @adapter: Driver specific private data structure * * Will alloc memory to hold the vport parameters received on MailBox */ static int idpf_vport_params_buf_alloc(struct idpf_adapter *adapter) { … } /** * idpf_vc_core_init - Initialize state machine and get driver specific * resources * @adapter: Driver specific private structure * * This function will initialize the state machine and request all necessary * resources required by the device driver. Once the state machine is * initialized, allocate memory to store vport specific information and also * requests required interrupts. * * Returns 0 on success, -EAGAIN function will get called again, * otherwise negative on failure. */ int idpf_vc_core_init(struct idpf_adapter *adapter) { … } /** * idpf_vc_core_deinit - Device deinit routine * @adapter: Driver specific private structure * */ void idpf_vc_core_deinit(struct idpf_adapter *adapter) { … } /** * idpf_vport_alloc_vec_indexes - Get relative vector indexes * @vport: virtual port data struct * * This function requests the vector information required for the vport and * stores the vector indexes received from the 'global vector distribution' * in the vport's queue vectors array. * * Return 0 on success, error on failure */ int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport) { … } /** * idpf_vport_init - Initialize virtual port * @vport: virtual port to be initialized * @max_q: vport max queue info * * Will initialize vport with the info received through MB earlier */ void idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q) { … } /** * idpf_get_vec_ids - Initialize vector id from Mailbox parameters * @adapter: adapter structure to get the mailbox vector id * @vecids: Array of vector ids * @num_vecids: number of vector ids * @chunks: vector ids received over mailbox * * Will initialize the mailbox vector id which is received from the * get capabilities and data queue vector ids with ids received as * mailbox parameters. * Returns number of ids filled */ int idpf_get_vec_ids(struct idpf_adapter *adapter, u16 *vecids, int num_vecids, struct virtchnl2_vector_chunks *chunks) { … } /** * idpf_vport_get_queue_ids - Initialize queue id from Mailbox parameters * @qids: Array of queue ids * @num_qids: number of queue ids * @q_type: queue model * @chunks: queue ids received over mailbox * * Will initialize all queue ids with ids received as mailbox parameters * Returns number of ids filled */ static int idpf_vport_get_queue_ids(u32 *qids, int num_qids, u16 q_type, struct virtchnl2_queue_reg_chunks *chunks) { … } /** * __idpf_vport_queue_ids_init - Initialize queue ids from Mailbox parameters * @vport: virtual port for which the queues ids are initialized * @qids: queue ids * @num_qids: number of queue ids * @q_type: type of queue * * Will initialize all queue ids with ids received as mailbox * parameters. Returns number of queue ids initialized. */ static int __idpf_vport_queue_ids_init(struct idpf_vport *vport, const u32 *qids, int num_qids, u32 q_type) { … } /** * idpf_vport_queue_ids_init - Initialize queue ids from Mailbox parameters * @vport: virtual port for which the queues ids are initialized * * Will initialize all queue ids with ids received as mailbox parameters. * Returns 0 on success, negative if all the queues are not initialized. */ int idpf_vport_queue_ids_init(struct idpf_vport *vport) { … } /** * idpf_vport_adjust_qs - Adjust to new requested queues * @vport: virtual port data struct * * Renegotiate queues. Returns 0 on success, negative on failure. */ int idpf_vport_adjust_qs(struct idpf_vport *vport) { … } /** * idpf_is_capability_ena - Default implementation of capability checking * @adapter: Private data struct * @all: all or one flag * @field: caps field to check for flags * @flag: flag to check * * Return true if all capabilities are supported, false otherwise */ bool idpf_is_capability_ena(struct idpf_adapter *adapter, bool all, enum idpf_cap_field field, u64 flag) { … } /** * idpf_get_vport_id: Get vport id * @vport: virtual port structure * * Return vport id from the adapter persistent data */ u32 idpf_get_vport_id(struct idpf_vport *vport) { … } /** * idpf_mac_filter_async_handler - Async callback for mac filters * @adapter: private data struct * @xn: transaction for message * @ctlq_msg: received message * * In some scenarios driver can't sleep and wait for a reply (e.g.: stack is * holding rtnl_lock) when adding a new mac filter. It puts us in a difficult * situation to deal with errors returned on the reply. The best we can * ultimately do is remove it from our list of mac filters and report the * error. */ static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter, struct idpf_vc_xn *xn, const struct idpf_ctlq_msg *ctlq_msg) { … } /** * idpf_add_del_mac_filters - Add/del mac filters * @vport: Virtual port data structure * @np: Netdev private structure * @add: Add or delete flag * @async: Don't wait for return message * * Returns 0 on success, error on failure. **/ int idpf_add_del_mac_filters(struct idpf_vport *vport, struct idpf_netdev_priv *np, bool add, bool async) { … } /** * idpf_set_promiscuous - set promiscuous and send message to mailbox * @adapter: Driver specific private structure * @config_data: Vport specific config data * @vport_id: Vport identifier * * Request to enable promiscuous mode for the vport. Message is sent * asynchronously and won't wait for response. Returns 0 on success, negative * on failure; */ int idpf_set_promiscuous(struct idpf_adapter *adapter, struct idpf_vport_user_config_data *config_data, u32 vport_id) { … }