Commit 08135eec authored by Edward Cree's avatar Edward Cree Committed by David S. Miller
Browse files

sfc: add skeleton ef100 VF representors



No net_device_ops yet, just a placeholder netdev created per VF.

Signed-off-by: default avatarEdward Cree <ecree.xilinx@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 95287e1b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ sfc-y += efx.o efx_common.o efx_channels.o nic.o \
			   ef100.o ef100_nic.o ef100_netdev.o \
			   ef100_ethtool.o ef100_rx.o ef100_tx.o
sfc-$(CONFIG_SFC_MTD)	+= mtd.o
sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o
sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o

obj-$(CONFIG_SFC)	+= sfc.o

+1 −1
Original line number Diff line number Diff line
@@ -312,7 +312,7 @@ void ef100_remove_netdev(struct efx_probe_data *probe_data)
	unregister_netdevice_notifier(&efx->netdev_notifier);
#if defined(CONFIG_SFC_SRIOV)
	if (!efx->type->is_vf)
		efx_ef100_pci_sriov_disable(efx);
		efx_ef100_pci_sriov_disable(efx, true);
#endif

	ef100_unregister_netdev(efx);
+126 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
 * Driver for Solarflare network controllers and boards
 * Copyright 2019 Solarflare Communications Inc.
 * Copyright 2020-2022 Xilinx Inc.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation, incorporated herein by reference.
 */

#include "ef100_rep.h"
#include "ef100_nic.h"

static int efx_ef100_rep_init_struct(struct efx_nic *efx, struct efx_rep *efv)
{
	efv->parent = efx;
	INIT_LIST_HEAD(&efv->list);
	efv->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE |
			  NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
			  NETIF_MSG_IFUP | NETIF_MSG_RX_ERR |
			  NETIF_MSG_TX_ERR | NETIF_MSG_HW;
	return 0;
}

static const struct net_device_ops efx_ef100_rep_netdev_ops = {
};

static const struct ethtool_ops efx_ef100_rep_ethtool_ops = {
};

static struct efx_rep *efx_ef100_rep_create_netdev(struct efx_nic *efx,
						   unsigned int i)
{
	struct net_device *net_dev;
	struct efx_rep *efv;
	int rc;

	net_dev = alloc_etherdev_mq(sizeof(*efv), 1);
	if (!net_dev)
		return ERR_PTR(-ENOMEM);

	efv = netdev_priv(net_dev);
	rc = efx_ef100_rep_init_struct(efx, efv);
	if (rc)
		goto fail1;
	efv->net_dev = net_dev;
	rtnl_lock();
	spin_lock_bh(&efx->vf_reps_lock);
	list_add_tail(&efv->list, &efx->vf_reps);
	spin_unlock_bh(&efx->vf_reps_lock);
	netif_carrier_off(net_dev);
	netif_tx_stop_all_queues(net_dev);
	rtnl_unlock();

	net_dev->netdev_ops = &efx_ef100_rep_netdev_ops;
	net_dev->ethtool_ops = &efx_ef100_rep_ethtool_ops;
	net_dev->min_mtu = EFX_MIN_MTU;
	net_dev->max_mtu = EFX_MAX_MTU;
	return efv;
fail1:
	free_netdev(net_dev);
	return ERR_PTR(rc);
}

static void efx_ef100_rep_destroy_netdev(struct efx_rep *efv)
{
	struct efx_nic *efx = efv->parent;

	spin_lock_bh(&efx->vf_reps_lock);
	list_del(&efv->list);
	spin_unlock_bh(&efx->vf_reps_lock);
	free_netdev(efv->net_dev);
}

int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i)
{
	struct efx_rep *efv;
	int rc;

	efv = efx_ef100_rep_create_netdev(efx, i);
	if (IS_ERR(efv)) {
		rc = PTR_ERR(efv);
		pci_err(efx->pci_dev,
			"Failed to create representor for VF %d, rc %d\n", i,
			rc);
		return rc;
	}
	rc = register_netdev(efv->net_dev);
	if (rc) {
		pci_err(efx->pci_dev,
			"Failed to register representor for VF %d, rc %d\n",
			i, rc);
		goto fail;
	}
	pci_dbg(efx->pci_dev, "Representor for VF %d is %s\n", i,
		efv->net_dev->name);
	return 0;
fail:
	efx_ef100_rep_destroy_netdev(efv);
	return rc;
}

void efx_ef100_vfrep_destroy(struct efx_nic *efx, struct efx_rep *efv)
{
	struct net_device *rep_dev;

	rep_dev = efv->net_dev;
	if (!rep_dev)
		return;
	netif_dbg(efx, drv, rep_dev, "Removing VF representor\n");
	unregister_netdev(rep_dev);
	efx_ef100_rep_destroy_netdev(efv);
}

void efx_ef100_fini_vfreps(struct efx_nic *efx)
{
	struct ef100_nic_data *nic_data = efx->nic_data;
	struct efx_rep *efv, *next;

	if (!nic_data->grp_mae)
		return;

	list_for_each_entry_safe(efv, next, &efx->vf_reps, list)
		efx_ef100_vfrep_destroy(efx, efv);
}
+37 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
 * Driver for Solarflare network controllers and boards
 * Copyright 2019 Solarflare Communications Inc.
 * Copyright 2020-2022 Xilinx Inc.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation, incorporated herein by reference.
 */

/* Handling for ef100 representor netdevs */
#ifndef EF100_REP_H
#define EF100_REP_H

#include "net_driver.h"

/**
 * struct efx_rep - Private data for an Efx representor
 *
 * @parent: the efx PF which manages this representor
 * @net_dev: representor netdevice
 * @msg_enable: log message enable flags
 * @list: entry on efx->vf_reps
 */
struct efx_rep {
	struct efx_nic *parent;
	struct net_device *net_dev;
	u32 msg_enable;
	struct list_head list;
};

int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i);
void efx_ef100_vfrep_destroy(struct efx_nic *efx, struct efx_rep *efv);
void efx_ef100_fini_vfreps(struct efx_nic *efx);

#endif /* EF100_REP_H */
+24 −8
Original line number Diff line number Diff line
@@ -11,46 +11,62 @@

#include "ef100_sriov.h"
#include "ef100_nic.h"
#include "ef100_rep.h"

static int efx_ef100_pci_sriov_enable(struct efx_nic *efx, int num_vfs)
{
	struct ef100_nic_data *nic_data = efx->nic_data;
	struct pci_dev *dev = efx->pci_dev;
	int rc;
	struct efx_rep *efv, *next;
	int rc, i;

	efx->vf_count = num_vfs;
	rc = pci_enable_sriov(dev, num_vfs);
	if (rc)
		goto fail;
		goto fail1;

	if (!nic_data->grp_mae)
		return 0;

fail:
	for (i = 0; i < num_vfs; i++) {
		rc = efx_ef100_vfrep_create(efx, i);
		if (rc)
			goto fail2;
	}
	return 0;

fail2:
	list_for_each_entry_safe(efv, next, &efx->vf_reps, list)
		efx_ef100_vfrep_destroy(efx, efv);
	pci_disable_sriov(dev);
fail1:
	netif_err(efx, probe, efx->net_dev, "Failed to enable SRIOV VFs\n");
	efx->vf_count = 0;
	return rc;
}

int efx_ef100_pci_sriov_disable(struct efx_nic *efx)
int efx_ef100_pci_sriov_disable(struct efx_nic *efx, bool force)
{
	struct pci_dev *dev = efx->pci_dev;
	unsigned int vfs_assigned;

	vfs_assigned = pci_vfs_assigned(dev);
	if (vfs_assigned) {
	if (vfs_assigned && !force) {
		netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; "
			   "please detach them before disabling SR-IOV\n");
		return -EBUSY;
	}

	efx_ef100_fini_vfreps(efx);
	if (!vfs_assigned)
		pci_disable_sriov(dev);

	return 0;
}

int efx_ef100_sriov_configure(struct efx_nic *efx, int num_vfs)
{
	if (num_vfs == 0)
		return efx_ef100_pci_sriov_disable(efx);
		return efx_ef100_pci_sriov_disable(efx, false);
	else
		return efx_ef100_pci_sriov_enable(efx, num_vfs);
}
Loading