// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2010-2012 Solarflare Communications Inc. */ #include <linux/pci.h> #include <linux/module.h> #include "net_driver.h" #include "efx.h" #include "efx_channels.h" #include "nic.h" #include "io.h" #include "mcdi.h" #include "filter.h" #include "mcdi_pcol.h" #include "farch_regs.h" #include "siena_sriov.h" #include "vfdi.h" /* Number of longs required to track all the VIs in a VF */ #define VI_MASK_LENGTH … /* Maximum number of RX queues supported */ #define VF_MAX_RX_QUEUES … /** * enum efx_vf_tx_filter_mode - TX MAC filtering behaviour * @VF_TX_FILTER_OFF: Disabled * @VF_TX_FILTER_AUTO: Enabled if MAC address assigned to VF and only * 2 TX queues allowed per VF. * @VF_TX_FILTER_ON: Enabled */ enum efx_vf_tx_filter_mode { … }; /** * struct siena_vf - Back-end resource and protocol state for a PCI VF * @efx: The Efx NIC owning this VF * @pci_rid: The PCI requester ID for this VF * @pci_name: The PCI name (formatted address) of this VF * @index: Index of VF within its port and PF. * @req: VFDI incoming request work item. Incoming USR_EV events are received * by the NAPI handler, but must be handled by executing MCDI requests * inside a work item. * @req_addr: VFDI incoming request DMA address (in VF's PCI address space). * @req_type: Expected next incoming (from VF) %VFDI_EV_TYPE member. * @req_seqno: Expected next incoming (from VF) %VFDI_EV_SEQ member. * @msg_seqno: Next %VFDI_EV_SEQ member to reply to VF. Protected by * @status_lock * @busy: VFDI request queued to be processed or being processed. Receiving * a VFDI request when @busy is set is an error condition. * @buf: Incoming VFDI requests are DMA from the VF into this buffer. * @buftbl_base: Buffer table entries for this VF start at this index. * @rx_filtering: Receive filtering has been requested by the VF driver. * @rx_filter_flags: The flags sent in the %VFDI_OP_INSERT_FILTER request. * @rx_filter_qid: VF relative qid for RX filter requested by VF. * @rx_filter_id: Receive MAC filter ID. Only one filter per VF is supported. * @tx_filter_mode: Transmit MAC filtering mode. * @tx_filter_id: Transmit MAC filter ID. * @addr: The MAC address and outer vlan tag of the VF. * @status_addr: VF DMA address of page for &struct vfdi_status updates. * @status_lock: Mutex protecting @msg_seqno, @status_addr, @addr, * @peer_page_addrs and @peer_page_count from simultaneous * updates by the VM and consumption by * efx_siena_sriov_update_vf_addr() * @peer_page_addrs: Pointer to an array of guest pages for local addresses. * @peer_page_count: Number of entries in @peer_page_count. * @evq0_addrs: Array of guest pages backing evq0. * @evq0_count: Number of entries in @evq0_addrs. * @flush_waitq: wait queue used by %VFDI_OP_FINI_ALL_QUEUES handler * to wait for flush completions. * @txq_lock: Mutex for TX queue allocation. * @txq_mask: Mask of initialized transmit queues. * @txq_count: Number of initialized transmit queues. * @rxq_mask: Mask of initialized receive queues. * @rxq_count: Number of initialized receive queues. * @rxq_retry_mask: Mask or receive queues that need to be flushed again * due to flush failure. * @rxq_retry_count: Number of receive queues in @rxq_retry_mask. * @reset_work: Work item to schedule a VF reset. */ struct siena_vf { … }; struct efx_memcpy_req { … }; /** * struct efx_local_addr - A MAC address on the vswitch without a VF. * * Siena does not have a switch, so VFs can't transmit data to each * other. Instead the VFs must be made aware of the local addresses * on the vswitch, so that they can arrange for an alternative * software datapath to be used. * * @link: List head for insertion into efx->local_addr_list. * @addr: Ethernet address */ struct efx_local_addr { … }; /** * struct efx_endpoint_page - Page of vfdi_endpoint structures * * @link: List head for insertion into efx->local_page_list. * @ptr: Pointer to page. * @addr: DMA address of page. */ struct efx_endpoint_page { … }; /* Buffer table entries are reserved txq0,rxq0,evq0,txq1,rxq1,evq1 */ #define EFX_BUFTBL_TXQ_BASE(_vf, _qid) … #define EFX_BUFTBL_RXQ_BASE(_vf, _qid) … #define EFX_BUFTBL_EVQ_BASE(_vf, _qid) … #define EFX_FIELD_MASK(_field) … /* VFs can only use this many transmit channels */ static unsigned int vf_max_tx_channels = …; module_param(vf_max_tx_channels, uint, 0444); MODULE_PARM_DESC(…) …; static int max_vfs = …; module_param(max_vfs, int, 0444); MODULE_PARM_DESC(…) …; /* Workqueue used by VFDI communication. We can't use the global * workqueue because it may be running the VF driver's probe() * routine, which will be blocked there waiting for a VFDI response. */ static struct workqueue_struct *vfdi_workqueue; static unsigned abs_index(struct siena_vf *vf, unsigned index) { … } static int efx_siena_sriov_cmd(struct efx_nic *efx, bool enable, unsigned *vi_scale_out, unsigned *vf_total_out) { … } static void efx_siena_sriov_usrev(struct efx_nic *efx, bool enabled) { … } static int efx_siena_sriov_memcpy(struct efx_nic *efx, struct efx_memcpy_req *req, unsigned int count) { … } /* The TX filter is entirely controlled by this driver, and is modified * underneath the feet of the VF */ static void efx_siena_sriov_reset_tx_filter(struct siena_vf *vf) { … } /* The RX filter is managed here on behalf of the VF driver */ static void efx_siena_sriov_reset_rx_filter(struct siena_vf *vf) { … } static void __efx_siena_sriov_update_vf_addr(struct siena_vf *vf) { … } /* Push the peer list to this VF. The caller must hold status_lock to interlock * with VFDI requests, and they must be serialised against manipulation of * local_page_list, either by acquiring local_lock or by running from * efx_siena_sriov_peer_work() */ static void __efx_siena_sriov_push_vf_status(struct siena_vf *vf) { … } static void efx_siena_sriov_bufs(struct efx_nic *efx, unsigned offset, u64 *addr, unsigned count) { … } static bool bad_vf_index(struct efx_nic *efx, unsigned index) { … } static bool bad_buf_count(unsigned buf_count, unsigned max_entry_count) { … } /* Check that VI specified by per-port index belongs to a VF. * Optionally set VF index and VI index within the VF. */ static bool map_vi_index(struct efx_nic *efx, unsigned abs_index, struct siena_vf **vf_out, unsigned *rel_index_out) { … } static int efx_vfdi_init_evq(struct siena_vf *vf) { … } static int efx_vfdi_init_rxq(struct siena_vf *vf) { … } static int efx_vfdi_init_txq(struct siena_vf *vf) { … } /* Returns true when efx_vfdi_fini_all_queues should wake */ static bool efx_vfdi_flush_wake(struct siena_vf *vf) { … } static void efx_vfdi_flush_clear(struct siena_vf *vf) { … } static int efx_vfdi_fini_all_queues(struct siena_vf *vf) { … } static int efx_vfdi_insert_filter(struct siena_vf *vf) { … } static int efx_vfdi_remove_all_filters(struct siena_vf *vf) { … } static int efx_vfdi_set_status_page(struct siena_vf *vf) { … } static int efx_vfdi_clear_status_page(struct siena_vf *vf) { … } efx_vfdi_op_t; static const efx_vfdi_op_t vfdi_ops[VFDI_OP_LIMIT] = …; static void efx_siena_sriov_vfdi(struct work_struct *work) { … } /* After a reset the event queues inside the guests no longer exist. Fill the * event ring in guest memory with VFDI reset events, then (re-initialise) the * event queue to raise an interrupt. The guest driver will then recover. */ static void efx_siena_sriov_reset_vf(struct siena_vf *vf, struct efx_buffer *buffer) { … } static void efx_siena_sriov_reset_vf_work(struct work_struct *work) { … } static void efx_siena_sriov_handle_no_channel(struct efx_nic *efx) { … } static int efx_siena_sriov_probe_channel(struct efx_channel *channel) { … } static void efx_siena_sriov_get_channel_name(struct efx_channel *channel, char *buf, size_t len) { … } static const struct efx_channel_type efx_siena_sriov_channel_type = …; void efx_siena_sriov_probe(struct efx_nic *efx) { … } /* Copy the list of individual addresses into the vfdi_status.peers * array and auxiliary pages, protected by %local_lock. Drop that lock * and then broadcast the address list to every VF. */ static void efx_siena_sriov_peer_work(struct work_struct *data) { … } static void efx_siena_sriov_free_local(struct efx_nic *efx) { … } static int efx_siena_sriov_vf_alloc(struct efx_nic *efx) { … } static void efx_siena_sriov_vfs_fini(struct efx_nic *efx) { … } static int efx_siena_sriov_vfs_init(struct efx_nic *efx) { … } int efx_siena_sriov_init(struct efx_nic *efx) { … } void efx_siena_sriov_fini(struct efx_nic *efx) { … } void efx_siena_sriov_event(struct efx_channel *channel, efx_qword_t *event) { … } void efx_siena_sriov_flr(struct efx_nic *efx, unsigned vf_i) { … } int efx_siena_sriov_mac_address_changed(struct efx_nic *efx) { … } void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event) { … } void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event) { … } /* Called from napi. Schedule the reset work item */ void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq) { … } /* Reset all VFs */ void efx_siena_sriov_reset(struct efx_nic *efx) { … } int efx_init_sriov(void) { … } void efx_fini_sriov(void) { … } int efx_siena_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, const u8 *mac) { … } int efx_siena_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan, u8 qos) { … } int efx_siena_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i, bool spoofchk) { … } int efx_siena_sriov_get_vf_config(struct efx_nic *efx, int vf_i, struct ifla_vf_info *ivi) { … } bool efx_siena_sriov_wanted(struct efx_nic *efx) { … } int efx_siena_sriov_configure(struct efx_nic *efx, int num_vfs) { … }