linux/drivers/net/ethernet/sfc/siena/siena_sriov.c

// 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)
{}