/* * Allocate an L2T entry for use by a switching rule. Such need to be * explicitly freed and while busy they are not on any hash chain, so normal * address resolution updates do not see them. */ struct l2t_entry * t4_l2t_alloc_switching(struct adapter *sc, uint16_t vlan, uint8_t port, uint8_t *eth_addr) { struct l2t_data *d = sc->l2t; struct l2t_entry *e; int rc; rw_wlock(&d->lock); e = find_or_alloc_l2e(d, vlan, port, eth_addr); if (e) { if (atomic_load_acq_int(&e->refcnt) == 0) { mtx_lock(&e->lock); /* avoid race with t4_l2t_free */ e->wrq = &sc->sge.ctrlq[0]; e->iqid = sc->sge.fwq.abs_id; e->state = L2T_STATE_SWITCHING; e->vlan = vlan; e->lport = port; memcpy(e->dmac, eth_addr, ETHER_ADDR_LEN); atomic_store_rel_int(&e->refcnt, 1); atomic_subtract_int(&d->nfree, 1); rc = t4_write_l2e(e, 0); mtx_unlock(&e->lock); if (rc != 0) e = NULL; } else { MPASS(e->vlan == vlan); MPASS(e->lport == port); atomic_add_int(&e->refcnt, 1); } } rw_wunlock(&d->lock); return (e); }
/* * Sets/updates the contents of a switching L2T entry that has been allocated * with an earlier call to @t4_l2t_alloc_switching. */ int t4_l2t_set_switching(struct adapter *sc, struct l2t_entry *e, uint16_t vlan, uint8_t port, uint8_t *eth_addr) { int rc; e->vlan = vlan; e->lport = port; memcpy(e->dmac, eth_addr, ETHER_ADDR_LEN); mtx_lock(&e->lock); rc = t4_write_l2e(sc, e, 0); mtx_unlock(&e->lock); return (rc); }
static void update_entry(struct adapter *sc, struct l2t_entry *e, uint8_t *lladdr, uint16_t vtag) { mtx_assert(&e->lock, MA_OWNED); /* * The entry may be in active use (e->refcount > 0) or not. We update * it even when it's not as this simplifies the case where we decide to * reuse the entry later. */ if (lladdr == NULL && (e->state == L2T_STATE_RESOLVING || e->state == L2T_STATE_FAILED)) { /* * Never got a valid L2 address for this one. Just mark it as * failed instead of removing it from the hash (for which we'd * need to wlock the table). */ e->state = L2T_STATE_FAILED; resolution_failed(e); return; } else if (lladdr == NULL) { /* Valid or already-stale entry was deleted (or expired) */ KASSERT(e->state == L2T_STATE_VALID || e->state == L2T_STATE_STALE, ("%s: lladdr NULL, state %d", __func__, e->state)); e->state = L2T_STATE_STALE; } else { if (e->state == L2T_STATE_RESOLVING || e->state == L2T_STATE_FAILED || memcmp(e->dmac, lladdr, ETHER_ADDR_LEN)) { /* unresolved -> resolved; or dmac changed */ memcpy(e->dmac, lladdr, ETHER_ADDR_LEN); e->vlan = vtag; t4_write_l2e(sc, e, 1); } e->state = L2T_STATE_VALID; } }