Commit a6a15aca authored by Alejandro Lucero's avatar Alejandro Lucero Committed by Paolo Abeni
Browse files

sfc: enumerate mports in ef100



MAE ports (mports) are the ports on the EF100 embedded switch such
as networking PCIe functions, the physical port, and potentially
others.

Signed-off-by: default avatarAlejandro Lucero <alejandro.lucero-palau@amd.com>
Acked-by: default avatarMartin Habets <habetsm.xilinx@gmail.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 14743ddd
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -747,6 +747,19 @@ static int efx_ef100_get_base_mport(struct efx_nic *efx)
			   id);
	nic_data->base_mport = id;
	nic_data->have_mport = true;

	/* Construct mport selector for "calling PF" */
	efx_mae_mport_uplink(efx, &selector);
	/* Look up actual mport ID */
	rc = efx_mae_lookup_mport(efx, selector, &id);
	if (rc)
		return rc;
	if (id >> 16)
		netif_warn(efx, probe, efx->net_dev, "Bad own m-port id %#x\n",
			   id);
	nic_data->own_mport = id;
	nic_data->have_own_mport = true;

	return 0;
}
#endif
@@ -1126,6 +1139,14 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
			   rc);
	}

	rc = efx_init_mae(efx);
	if (rc)
		netif_warn(efx, probe, net_dev,
			   "Failed to init MAE rc %d; representors will not function\n",
			   rc);
	else
		efx_ef100_init_reps(efx);

	rc = efx_init_tc(efx);
	if (rc) {
		/* Either we don't have an MAE at all (i.e. legacy v-switching),
@@ -1157,6 +1178,12 @@ void ef100_remove(struct efx_nic *efx)
{
	struct ef100_nic_data *nic_data = efx->nic_data;

#ifdef CONFIG_SFC_SRIOV
	if (efx->mae) {
		efx_ef100_fini_reps(efx);
		efx_fini_mae(efx);
	}
#endif
	efx_mcdi_detach(efx);
	efx_mcdi_fini(efx);
	if (nic_data)
+4 −0
Original line number Diff line number Diff line
@@ -74,6 +74,10 @@ struct ef100_nic_data {
	u64 stats[EF100_STAT_COUNT];
	u32 base_mport;
	bool have_mport; /* base_mport was populated successfully */
	u32 own_mport;
	u32 local_mae_intf; /* interface_idx that corresponds to us, in mport enumerate */
	bool have_own_mport; /* own_mport was populated successfully */
	bool have_local_intf; /* local_mae_intf was populated successfully */
	bool grp_mae; /* MAE Privilege */
	u16 tso_max_hdr_len;
	u16 tso_max_payload_num_segs;
+22 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
 * by the Free Software Foundation, incorporated herein by reference.
 */

#include <linux/rhashtable.h>
#include "ef100_rep.h"
#include "ef100_netdev.h"
#include "ef100_nic.h"
@@ -341,6 +342,27 @@ void efx_ef100_fini_vfreps(struct efx_nic *efx)
		efx_ef100_vfrep_destroy(efx, efv);
}

void efx_ef100_init_reps(struct efx_nic *efx)
{
	struct ef100_nic_data *nic_data = efx->nic_data;
	int rc;

	nic_data->have_local_intf = false;
	rc = efx_mae_enumerate_mports(efx);
	if (rc)
		pci_warn(efx->pci_dev,
			 "Could not enumerate mports (rc=%d), are we admin?",
			 rc);
}

void efx_ef100_fini_reps(struct efx_nic *efx)
{
	struct efx_mae *mae = efx->mae;

	rhashtable_free_and_destroy(&mae->mports_ht, efx_mae_remove_mport,
				    NULL);
}

static int efx_ef100_rep_poll(struct napi_struct *napi, int weight)
{
	struct efx_rep *efv = container_of(napi, struct efx_rep, napi);
+2 −0
Original line number Diff line number Diff line
@@ -67,4 +67,6 @@ void efx_ef100_rep_rx_packet(struct efx_rep *efv, struct efx_rx_buffer *rx_buf);
 */
struct efx_rep *efx_ef100_find_rep_by_mport(struct efx_nic *efx, u16 mport);
extern const struct net_device_ops efx_ef100_rep_netdev_ops;
void efx_ef100_init_reps(struct efx_nic *efx);
void efx_ef100_fini_reps(struct efx_nic *efx);
#endif /* EF100_REP_H */
+191 −0
Original line number Diff line number Diff line
@@ -9,8 +9,11 @@
 * by the Free Software Foundation, incorporated herein by reference.
 */

#include <linux/rhashtable.h>
#include "ef100_nic.h"
#include "mae.h"
#include "mcdi.h"
#include "mcdi_pcol.h"
#include "mcdi_pcol_mae.h"

int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label)
@@ -490,6 +493,163 @@ static bool efx_mae_asl_id(u32 id)
	return !!(id & BIT(31));
}

/* mport handling */
static const struct rhashtable_params efx_mae_mports_ht_params = {
	.key_len	= sizeof(u32),
	.key_offset	= offsetof(struct mae_mport_desc, mport_id),
	.head_offset	= offsetof(struct mae_mport_desc, linkage),
};

struct mae_mport_desc *efx_mae_get_mport(struct efx_nic *efx, u32 mport_id)
{
	return rhashtable_lookup_fast(&efx->mae->mports_ht, &mport_id,
				      efx_mae_mports_ht_params);
}

static int efx_mae_add_mport(struct efx_nic *efx, struct mae_mport_desc *desc)
{
	struct efx_mae *mae = efx->mae;
	int rc;

	rc = rhashtable_insert_fast(&mae->mports_ht, &desc->linkage,
				    efx_mae_mports_ht_params);

	if (rc) {
		pci_err(efx->pci_dev, "Failed to insert MPORT %08x, rc %d\n",
			desc->mport_id, rc);
		kfree(desc);
		return rc;
	}

	return rc;
}

void efx_mae_remove_mport(void *desc, void *arg)
{
	struct mae_mport_desc *mport = desc;

	synchronize_rcu();
	kfree(mport);
}

static int efx_mae_process_mport(struct efx_nic *efx,
				 struct mae_mport_desc *desc)
{
	struct ef100_nic_data *nic_data = efx->nic_data;
	struct mae_mport_desc *mport;

	mport = efx_mae_get_mport(efx, desc->mport_id);
	if (!IS_ERR_OR_NULL(mport)) {
		netif_err(efx, drv, efx->net_dev,
			  "mport with id %u does exist!!!\n", desc->mport_id);
		return -EEXIST;
	}

	if (nic_data->have_own_mport &&
	    desc->mport_id == nic_data->own_mport) {
		WARN_ON(desc->mport_type != MAE_MPORT_DESC_MPORT_TYPE_VNIC);
		WARN_ON(desc->vnic_client_type !=
			MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION);
		nic_data->local_mae_intf = desc->interface_idx;
		nic_data->have_local_intf = true;
		pci_dbg(efx->pci_dev, "MAE interface_idx is %u\n",
			nic_data->local_mae_intf);
	}

	return efx_mae_add_mport(efx, desc);
}

#define MCDI_MPORT_JOURNAL_LEN \
	ALIGN(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4)

int efx_mae_enumerate_mports(struct efx_nic *efx)
{
	efx_dword_t *outbuf = kzalloc(MCDI_MPORT_JOURNAL_LEN, GFP_KERNEL);
	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN);
	MCDI_DECLARE_STRUCT_PTR(desc);
	size_t outlen, stride, count;
	int rc = 0, i;

	if (!outbuf)
		return -ENOMEM;
	do {
		rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_READ_JOURNAL, inbuf,
				  sizeof(inbuf), outbuf,
				  MCDI_MPORT_JOURNAL_LEN, &outlen);
		if (rc)
			goto fail;
		if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST) {
			rc = -EIO;
			goto fail;
		}
		count = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT);
		if (!count)
			continue; /* not break; we want to look at MORE flag */
		stride = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC);
		if (stride < MAE_MPORT_DESC_LEN) {
			rc = -EIO;
			goto fail;
		}
		if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LEN(count * stride)) {
			rc = -EIO;
			goto fail;
		}

		for (i = 0; i < count; i++) {
			struct mae_mport_desc *d;

			d = kzalloc(sizeof(*d), GFP_KERNEL);
			if (!d) {
				rc = -ENOMEM;
				goto fail;
			}

			desc = (efx_dword_t *)
				_MCDI_PTR(outbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST +
					  i * stride);
			d->mport_id = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_MPORT_ID);
			d->flags = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_FLAGS);
			d->caller_flags = MCDI_STRUCT_DWORD(desc,
							    MAE_MPORT_DESC_CALLER_FLAGS);
			d->mport_type = MCDI_STRUCT_DWORD(desc,
							  MAE_MPORT_DESC_MPORT_TYPE);
			switch (d->mport_type) {
			case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
				d->port_idx = MCDI_STRUCT_DWORD(desc,
								MAE_MPORT_DESC_NET_PORT_IDX);
				break;
			case MAE_MPORT_DESC_MPORT_TYPE_ALIAS:
				d->alias_mport_id = MCDI_STRUCT_DWORD(desc,
								      MAE_MPORT_DESC_ALIAS_DELIVER_MPORT_ID);
				break;
			case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
				d->vnic_client_type = MCDI_STRUCT_DWORD(desc,
									MAE_MPORT_DESC_VNIC_CLIENT_TYPE);
				d->interface_idx = MCDI_STRUCT_DWORD(desc,
								     MAE_MPORT_DESC_VNIC_FUNCTION_INTERFACE);
				d->pf_idx = MCDI_STRUCT_WORD(desc,
							     MAE_MPORT_DESC_VNIC_FUNCTION_PF_IDX);
			d->vf_idx = MCDI_STRUCT_WORD(desc,
						     MAE_MPORT_DESC_VNIC_FUNCTION_VF_IDX);
				break;
			default:
				/* Unknown mport_type, just accept it */
				break;
			}
			rc = efx_mae_process_mport(efx, d);
			/* Any failure will be due to memory allocation faiure,
			 * so there is no point to try subsequent entries.
			 */
			if (rc)
				goto fail;
		}
	} while (MCDI_FIELD(outbuf, MAE_MPORT_READ_JOURNAL_OUT, MORE) &&
		 !WARN_ON(!count));
fail:
	kfree(outbuf);
	return rc;
}

int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
{
	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
@@ -805,3 +965,34 @@ int efx_mae_delete_rule(struct efx_nic *efx, u32 id)
		return -EIO;
	return 0;
}

int efx_init_mae(struct efx_nic *efx)
{
	struct ef100_nic_data *nic_data = efx->nic_data;
	struct efx_mae *mae;
	int rc;

	if (!nic_data->have_mport)
		return -EINVAL;

	mae = kmalloc(sizeof(*mae), GFP_KERNEL);
	if (!mae)
		return -ENOMEM;

	rc = rhashtable_init(&mae->mports_ht, &efx_mae_mports_ht_params);
	if (rc < 0) {
		kfree(mae);
		return rc;
	}
	efx->mae = mae;
	mae->efx = efx;
	return 0;
}

void efx_fini_mae(struct efx_nic *efx)
{
	struct efx_mae *mae = efx->mae;

	kfree(mae);
	efx->mae = NULL;
}
Loading