+static struct sfc_mae_mac_addr *
+sfc_mae_mac_addr_attach(struct sfc_adapter *sa,
+ const uint8_t addr_bytes[EFX_MAC_ADDR_LEN])
+{
+ struct sfc_mae_mac_addr *mac_addr;
+ struct sfc_mae *mae = &sa->mae;
+
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+ TAILQ_FOREACH(mac_addr, &mae->mac_addrs, entries) {
+ if (memcmp(mac_addr->addr_bytes, addr_bytes,
+ EFX_MAC_ADDR_LEN) == 0) {
+ sfc_dbg(sa, "attaching to mac_addr=%p", mac_addr);
+ ++(mac_addr->refcnt);
+ return mac_addr;
+ }
+ }
+
+ return NULL;
+}
+
+static int
+sfc_mae_mac_addr_add(struct sfc_adapter *sa,
+ const uint8_t addr_bytes[EFX_MAC_ADDR_LEN],
+ struct sfc_mae_mac_addr **mac_addrp)
+{
+ struct sfc_mae_mac_addr *mac_addr;
+ struct sfc_mae *mae = &sa->mae;
+
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+ mac_addr = rte_zmalloc("sfc_mae_mac_addr", sizeof(*mac_addr), 0);
+ if (mac_addr == NULL)
+ return ENOMEM;
+
+ rte_memcpy(mac_addr->addr_bytes, addr_bytes, EFX_MAC_ADDR_LEN);
+
+ mac_addr->refcnt = 1;
+ mac_addr->fw_rsrc.mac_id.id = EFX_MAE_RSRC_ID_INVALID;
+
+ TAILQ_INSERT_TAIL(&mae->mac_addrs, mac_addr, entries);
+
+ *mac_addrp = mac_addr;
+
+ sfc_dbg(sa, "added mac_addr=%p", mac_addr);
+
+ return 0;
+}
+
+static void
+sfc_mae_mac_addr_del(struct sfc_adapter *sa, struct sfc_mae_mac_addr *mac_addr)
+{
+ struct sfc_mae *mae = &sa->mae;
+
+ if (mac_addr == NULL)
+ return;
+
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
+ SFC_ASSERT(mac_addr->refcnt != 0);
+
+ --(mac_addr->refcnt);
+
+ if (mac_addr->refcnt != 0)
+ return;
+
+ if (mac_addr->fw_rsrc.mac_id.id != EFX_MAE_RSRC_ID_INVALID ||
+ mac_addr->fw_rsrc.refcnt != 0) {
+ sfc_err(sa, "deleting mac_addr=%p abandons its FW resource: MAC_ID=0x%08x, refcnt=%u",
+ mac_addr, mac_addr->fw_rsrc.mac_id.id,
+ mac_addr->fw_rsrc.refcnt);
+ }
+
+ TAILQ_REMOVE(&mae->mac_addrs, mac_addr, entries);
+ rte_free(mac_addr);
+
+ sfc_dbg(sa, "deleted mac_addr=%p", mac_addr);
+}
+
+enum sfc_mae_mac_addr_type {
+ SFC_MAE_MAC_ADDR_DST,
+ SFC_MAE_MAC_ADDR_SRC
+};
+
+static int
+sfc_mae_mac_addr_enable(struct sfc_adapter *sa,
+ struct sfc_mae_mac_addr *mac_addr,
+ enum sfc_mae_mac_addr_type type,
+ efx_mae_actions_t *aset_spec)
+{
+ struct sfc_mae_fw_rsrc *fw_rsrc;
+ int rc = 0;
+
+ if (mac_addr == NULL)
+ return 0;
+
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+ fw_rsrc = &mac_addr->fw_rsrc;
+
+ if (fw_rsrc->refcnt == 0) {
+ SFC_ASSERT(fw_rsrc->mac_id.id == EFX_MAE_RSRC_ID_INVALID);
+
+ rc = efx_mae_mac_addr_alloc(sa->nic, mac_addr->addr_bytes,
+ &fw_rsrc->mac_id);
+ if (rc != 0) {
+ sfc_err(sa, "failed to enable mac_addr=%p: %s",
+ mac_addr, strerror(rc));
+ return rc;
+ }
+ }
+
+ switch (type) {
+ case SFC_MAE_MAC_ADDR_DST:
+ rc = efx_mae_action_set_fill_in_dst_mac_id(aset_spec,
+ &fw_rsrc->mac_id);
+ break;
+ case SFC_MAE_MAC_ADDR_SRC:
+ rc = efx_mae_action_set_fill_in_src_mac_id(aset_spec,
+ &fw_rsrc->mac_id);
+ break;
+ default:
+ rc = EINVAL;
+ break;
+ }
+
+ if (rc != 0) {
+ if (fw_rsrc->refcnt == 0) {
+ (void)efx_mae_mac_addr_free(sa->nic, &fw_rsrc->mac_id);
+ fw_rsrc->mac_id.id = EFX_MAE_RSRC_ID_INVALID;
+ }
+
+ sfc_err(sa, "cannot fill in MAC address entry ID: %s",
+ strerror(rc));
+
+ return rc;
+ }
+
+ if (fw_rsrc->refcnt == 0) {
+ sfc_dbg(sa, "enabled mac_addr=%p: MAC_ID=0x%08x",
+ mac_addr, fw_rsrc->mac_id.id);
+ }
+
+ ++(fw_rsrc->refcnt);
+
+ return 0;
+}
+
+static void
+sfc_mae_mac_addr_disable(struct sfc_adapter *sa,
+ struct sfc_mae_mac_addr *mac_addr)
+{
+ struct sfc_mae_fw_rsrc *fw_rsrc;
+ int rc;
+
+ if (mac_addr == NULL)
+ return;
+
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+ fw_rsrc = &mac_addr->fw_rsrc;
+
+ if (fw_rsrc->mac_id.id == EFX_MAE_RSRC_ID_INVALID ||
+ fw_rsrc->refcnt == 0) {
+ sfc_err(sa, "failed to disable mac_addr=%p: already disabled; MAC_ID=0x%08x, refcnt=%u",
+ mac_addr, fw_rsrc->mac_id.id, fw_rsrc->refcnt);
+ return;
+ }
+
+ if (fw_rsrc->refcnt == 1) {
+ rc = efx_mae_mac_addr_free(sa->nic, &fw_rsrc->mac_id);
+ if (rc == 0) {
+ sfc_dbg(sa, "disabled mac_addr=%p with MAC_ID=0x%08x",
+ mac_addr, fw_rsrc->mac_id.id);
+ } else {
+ sfc_err(sa, "failed to disable mac_addr=%p with MAC_ID=0x%08x: %s",
+ mac_addr, fw_rsrc->mac_id.id, strerror(rc));
+ }
+ fw_rsrc->mac_id.id = EFX_MAE_RSRC_ID_INVALID;
+ }
+
+ --(fw_rsrc->refcnt);
+}
+