Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/cxgbe/t4_l2t.c
Show First 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | for (p = &d->l2tab[e->hash].first; *p; p = &(*p)->next) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
e->state = L2T_STATE_UNUSED; | e->state = L2T_STATE_UNUSED; | ||||
return (e); | return (e); | ||||
} | } | ||||
static void | |||||
mk_write_l2e(struct adapter *sc, struct l2t_entry *e, int sync, int reply, | |||||
void *dst) | |||||
{ | |||||
struct cpl_l2t_write_req *req; | |||||
int idx; | |||||
req = dst; | |||||
idx = e->idx + sc->vres.l2t.start; | |||||
INIT_TP_WR(req, 0); | |||||
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, idx | | |||||
V_SYNC_WR(sync) | V_TID_QID(e->iqid))); | |||||
req->params = htons(V_L2T_W_PORT(e->lport) | V_L2T_W_NOREPLY(!reply)); | |||||
req->l2t_idx = htons(idx); | |||||
req->vlan = htons(e->vlan); | |||||
memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); | |||||
} | |||||
/* | /* | ||||
* Write an L2T entry. Must be called with the entry locked. | * Write an L2T entry. Must be called with the entry locked. | ||||
* The write may be synchronous or asynchronous. | * The write may be synchronous or asynchronous. | ||||
*/ | */ | ||||
int | int | ||||
t4_write_l2e(struct l2t_entry *e, int sync) | t4_write_l2e(struct l2t_entry *e, int sync) | ||||
{ | { | ||||
struct sge_wrq *wrq; | struct sge_wrq *wrq; | ||||
struct adapter *sc; | struct adapter *sc; | ||||
struct wrq_cookie cookie; | |||||
struct cpl_l2t_write_req *req; | struct cpl_l2t_write_req *req; | ||||
int idx; | struct wrq_cookie cookie; | ||||
mtx_assert(&e->lock, MA_OWNED); | mtx_assert(&e->lock, MA_OWNED); | ||||
MPASS(e->wrq != NULL); | MPASS(e->wrq != NULL); | ||||
wrq = e->wrq; | wrq = e->wrq; | ||||
sc = wrq->adapter; | sc = wrq->adapter; | ||||
req = start_wrq_wr(wrq, howmany(sizeof(*req), 16), &cookie); | req = start_wrq_wr(wrq, howmany(sizeof(*req), 16), &cookie); | ||||
if (req == NULL) | if (req == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
idx = e->idx + sc->vres.l2t.start; | mk_write_l2e(sc, e, sync, sync, req); | ||||
INIT_TP_WR(req, 0); | |||||
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, idx | | |||||
V_SYNC_WR(sync) | V_TID_QID(e->iqid))); | |||||
req->params = htons(V_L2T_W_PORT(e->lport) | V_L2T_W_NOREPLY(!sync)); | |||||
req->l2t_idx = htons(idx); | |||||
req->vlan = htons(e->vlan); | |||||
memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); | |||||
commit_wrq_wr(wrq, req, &cookie); | commit_wrq_wr(wrq, req, &cookie); | ||||
if (sync && e->state != L2T_STATE_SWITCHING) | if (sync && e->state != L2T_STATE_SWITCHING) | ||||
e->state = L2T_STATE_SYNC_WRITE; | e->state = L2T_STATE_SYNC_WRITE; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Allocate an L2T entry for use by a TLS connection. These entries are | |||||
* associated with a specific VLAN and destination MAC that never changes. | |||||
* However, multiple TLS connections might share a single entry. | |||||
* | |||||
* If a new L2T entry is allocated, a work request to initialize it is | |||||
* written to 'txq' and 'ndesc' will be set to 1. Otherwise, 'ndesc' | |||||
* will be set to 0. | |||||
* | |||||
* To avoid races, separate L2T entries are reserved for individual | |||||
* queues since the L2T entry update is written to a txq just prior to | |||||
* TLS work requests that will depend on it being written. | |||||
*/ | |||||
struct l2t_entry * | |||||
t4_l2t_alloc_tls(struct adapter *sc, struct sge_txq *txq, void *dst, | |||||
int *ndesc, uint16_t vlan, uint8_t port, uint8_t *eth_addr) | |||||
{ | |||||
struct l2t_data *d; | |||||
struct l2t_entry *e; | |||||
int i; | |||||
TXQ_LOCK_ASSERT_OWNED(txq); | |||||
d = sc->l2t; | |||||
*ndesc = 0; | |||||
rw_rlock(&d->lock); | |||||
/* First, try to find an existing entry. */ | |||||
for (i = 0; i < d->l2t_size; i++) { | |||||
e = &d->l2tab[i]; | |||||
if (e->state != L2T_STATE_TLS) | |||||
continue; | |||||
if (e->vlan == vlan && e->lport == port && | |||||
e->wrq == (struct sge_wrq *)txq && | |||||
memcmp(e->dmac, eth_addr, ETHER_ADDR_LEN) == 0) { | |||||
if (atomic_fetchadd_int(&e->refcnt, 1) == 0) { | |||||
/* | |||||
* This entry wasn't held but is still | |||||
* valid, so decrement nfree. | |||||
*/ | |||||
atomic_subtract_int(&d->nfree, 1); | |||||
} | |||||
KASSERT(e->refcnt > 0, | |||||
("%s: refcount overflow", __func__)); | |||||
rw_runlock(&d->lock); | |||||
return (e); | |||||
} | |||||
} | |||||
/* | |||||
* Don't bother rechecking if the upgrade fails since the txq is | |||||
* already locked. | |||||
*/ | |||||
if (!rw_try_upgrade(&d->lock)) { | |||||
rw_runlock(&d->lock); | |||||
rw_wlock(&d->lock); | |||||
} | |||||
/* Match not found, allocate a new entry. */ | |||||
e = t4_alloc_l2e(d); | |||||
if (e == NULL) { | |||||
rw_wunlock(&d->lock); | |||||
return (e); | |||||
} | |||||
/* Initialize the entry. */ | |||||
e->state = L2T_STATE_TLS; | |||||
e->vlan = vlan; | |||||
e->lport = port; | |||||
e->iqid = sc->sge.fwq.abs_id; | |||||
e->wrq = (struct sge_wrq *)txq; | |||||
memcpy(e->dmac, eth_addr, ETHER_ADDR_LEN); | |||||
atomic_store_rel_int(&e->refcnt, 1); | |||||
rw_wunlock(&d->lock); | |||||
/* Write out the work request. */ | |||||
*ndesc = howmany(sizeof(struct cpl_l2t_write_req), EQ_ESIZE); | |||||
MPASS(*ndesc == 1); | |||||
mk_write_l2e(sc, e, 1, 0, dst); | |||||
return (e); | |||||
} | |||||
/* | |||||
* Allocate an L2T entry for use by a switching rule. Such need to be | * 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 | * explicitly freed and while busy they are not on any hash chain, so normal | ||||
* address resolution updates do not see them. | * address resolution updates do not see them. | ||||
*/ | */ | ||||
struct l2t_entry * | struct l2t_entry * | ||||
t4_l2t_alloc_switching(struct adapter *sc, uint16_t vlan, uint8_t port, | t4_l2t_alloc_switching(struct adapter *sc, uint16_t vlan, uint8_t port, | ||||
uint8_t *eth_addr) | uint8_t *eth_addr) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | |||||
l2e_state(const struct l2t_entry *e) | l2e_state(const struct l2t_entry *e) | ||||
{ | { | ||||
switch (e->state) { | switch (e->state) { | ||||
case L2T_STATE_VALID: return 'V'; /* valid, fast-path entry */ | case L2T_STATE_VALID: return 'V'; /* valid, fast-path entry */ | ||||
case L2T_STATE_STALE: return 'S'; /* needs revalidation, but usable */ | case L2T_STATE_STALE: return 'S'; /* needs revalidation, but usable */ | ||||
case L2T_STATE_SYNC_WRITE: return 'W'; | case L2T_STATE_SYNC_WRITE: return 'W'; | ||||
case L2T_STATE_RESOLVING: return STAILQ_EMPTY(&e->wr_list) ? 'R' : 'A'; | case L2T_STATE_RESOLVING: return STAILQ_EMPTY(&e->wr_list) ? 'R' : 'A'; | ||||
case L2T_STATE_SWITCHING: return 'X'; | case L2T_STATE_SWITCHING: return 'X'; | ||||
case L2T_STATE_TLS: return 'T'; | |||||
default: return 'U'; | default: return 'U'; | ||||
} | } | ||||
} | } | ||||
int | int | ||||
sysctl_l2t(SYSCTL_HANDLER_ARGS) | sysctl_l2t(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct adapter *sc = arg1; | struct adapter *sc = arg1; | ||||
Show All 20 Lines | for (i = 0; i < l2t->l2t_size; i++, e++) { | ||||
if (e->state == L2T_STATE_UNUSED) | if (e->state == L2T_STATE_UNUSED) | ||||
goto skip; | goto skip; | ||||
if (header == 0) { | if (header == 0) { | ||||
sbuf_printf(sb, " Idx IP address " | sbuf_printf(sb, " Idx IP address " | ||||
"Ethernet address VLAN/P LP State Users Port"); | "Ethernet address VLAN/P LP State Users Port"); | ||||
header = 1; | header = 1; | ||||
} | } | ||||
if (e->state == L2T_STATE_SWITCHING) | if (e->state >= L2T_STATE_SWITCHING) | ||||
ip[0] = 0; | ip[0] = 0; | ||||
else { | else { | ||||
inet_ntop(e->ipv6 ? AF_INET6 : AF_INET, &e->addr[0], | inet_ntop(e->ipv6 ? AF_INET6 : AF_INET, &e->addr[0], | ||||
&ip[0], sizeof(ip)); | &ip[0], sizeof(ip)); | ||||
} | } | ||||
/* | /* | ||||
* XXX: IPv6 addresses may not align properly in the output. | * XXX: IPv6 addresses may not align properly in the output. | ||||
Show All 17 Lines |