sfc: enumerate mports in ef100
authorAlejandro Lucero <alejandro.lucero-palau@amd.com>
Wed, 15 Feb 2023 09:08:23 +0000 (09:08 +0000)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 16 Feb 2023 11:03:12 +0000 (12:03 +0100)
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: Alejandro Lucero <alejandro.lucero-palau@amd.com>
Acked-by: Martin Habets <habetsm.xilinx@gmail.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/sfc/ef100_nic.c
drivers/net/ethernet/sfc/ef100_nic.h
drivers/net/ethernet/sfc/ef100_rep.c
drivers/net/ethernet/sfc/ef100_rep.h
drivers/net/ethernet/sfc/mae.c
drivers/net/ethernet/sfc/mae.h
drivers/net/ethernet/sfc/mcdi.h
drivers/net/ethernet/sfc/net_driver.h

index ad686c6..07e7dca 100644 (file)
@@ -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)
index 0295933..496aea4 100644 (file)
@@ -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;
index 81ab22c..ebe7b12 100644 (file)
@@ -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);
index c21bc71..328ac0c 100644 (file)
@@ -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 */
index 583baf6..725a3ab 100644 (file)
@@ -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;
+}
index 72343e9..daa29d2 100644 (file)
@@ -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 */
index 5cb2026..b139b76 100644 (file)
@@ -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);                              \
index d036641..bc9efbf 100644 (file)
@@ -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;