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

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
......@@ -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)
......
......@@ -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;
......
......@@ -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);
......
......@@ -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 */
......@@ -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;
}
......@@ -27,6 +27,39 @@ void efx_mae_mport_mport(struct efx_nic *efx, u32 mport_id, u32 *out);
int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id);
struct mae_mport_desc {
u32 mport_id;
u32 flags;
u32 caller_flags; /* enum mae_mport_desc_caller_flags */
u32 mport_type; /* MAE_MPORT_DESC_MPORT_TYPE_* */
union {
u32 port_idx; /* for mport_type == NET_PORT */
u32 alias_mport_id; /* for mport_type == ALIAS */
struct { /* for mport_type == VNIC */
u32 vnic_client_type; /* MAE_MPORT_DESC_VNIC_CLIENT_TYPE_* */
u32 interface_idx;
u16 pf_idx;
u16 vf_idx;
};
};
struct rhash_head linkage;
};
int efx_mae_enumerate_mports(struct efx_nic *efx);
struct mae_mport_desc *efx_mae_get_mport(struct efx_nic *efx, u32 mport_id);
void efx_mae_put_mport(struct efx_nic *efx, struct mae_mport_desc *desc);
/**
* struct efx_mae - MAE information
*
* @efx: The associated NIC
* @mports_ht: m-port descriptions from MC_CMD_MAE_MPORT_READ_JOURNAL
*/
struct efx_mae {
struct efx_nic *efx;
struct rhashtable mports_ht;
};
int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue);
int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue);
void efx_mae_counters_grant_credits(struct work_struct *work);
......@@ -60,4 +93,7 @@ int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
u32 prio, u32 acts_id, u32 *id);
int efx_mae_delete_rule(struct efx_nic *efx, u32 id);
int efx_init_mae(struct efx_nic *efx);
void efx_fini_mae(struct efx_nic *efx);
void efx_mae_remove_mport(void *desc, void *arg);
#endif /* EF100_MAE_H */
......@@ -229,6 +229,9 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
#define MCDI_WORD(_buf, _field) \
((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) + \
le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field)))
#define MCDI_STRUCT_WORD(_buf, _field) \
((void)BUILD_BUG_ON_ZERO(_field ## _LEN != 2), \
le16_to_cpu(*(__force const __le16 *)MCDI_STRUCT_PTR(_buf, _field)))
/* Write a 16-bit field defined in the protocol as being big-endian. */
#define MCDI_STRUCT_SET_WORD_BE(_buf, _field, _value) do { \
BUILD_BUG_ON(_field ## _LEN != 2); \
......@@ -241,6 +244,8 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
EFX_POPULATE_DWORD_1(*_MCDI_STRUCT_DWORD(_buf, _field), EFX_DWORD_0, _value)
#define MCDI_DWORD(_buf, _field) \
EFX_DWORD_FIELD(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0)
#define MCDI_STRUCT_DWORD(_buf, _field) \
EFX_DWORD_FIELD(*_MCDI_STRUCT_DWORD(_buf, _field), EFX_DWORD_0)
/* Write a 32-bit field defined in the protocol as being big-endian. */
#define MCDI_STRUCT_SET_DWORD_BE(_buf, _field, _value) do { \
BUILD_BUG_ON(_field ## _LEN != 4); \
......
......@@ -845,6 +845,8 @@ enum efx_xdp_tx_queues_mode {
EFX_XDP_TX_QUEUES_BORROWED /* queues borrowed from net stack */
};
struct efx_mae;
/**
* struct efx_nic - an Efx NIC
* @name: Device name (net device name or bus id before net device registered)
......@@ -881,6 +883,7 @@ enum efx_xdp_tx_queues_mode {
* @msi_context: Context for each MSI
* @extra_channel_types: Types of extra (non-traffic) channels that
* should be allocated for this NIC
* @mae: Details of the Match Action Engine
* @xdp_tx_queue_count: Number of entries in %xdp_tx_queues.
* @xdp_tx_queues: Array of pointers to tx queues used for XDP transmit.
* @xdp_txq_queues_mode: XDP TX queues sharing strategy.
......@@ -1044,6 +1047,7 @@ struct efx_nic {
struct efx_msi_context msi_context[EFX_MAX_CHANNELS];
const struct efx_channel_type *
extra_channel_type[EFX_MAX_EXTRA_CHANNELS];
struct efx_mae *mae;
unsigned int xdp_tx_queue_count;
struct efx_tx_queue **xdp_tx_queues;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment