* 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)
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);
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;
+}
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);
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 */
#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); \
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); \