123af667fSShagun Agrawal /* SPDX-License-Identifier: BSD-3-Clause
223af667fSShagun Agrawal * Copyright(c) 2018 Chelsio Communications.
323af667fSShagun Agrawal * All rights reserved.
423af667fSShagun Agrawal */
589c8bd95SRahul Lakkireddy
689c8bd95SRahul Lakkireddy #include "base/common.h"
723af667fSShagun Agrawal #include "l2t.h"
823af667fSShagun Agrawal
923af667fSShagun Agrawal /**
1023af667fSShagun Agrawal * cxgbe_l2t_release - Release associated L2T entry
1123af667fSShagun Agrawal * @e: L2T entry to release
1223af667fSShagun Agrawal *
1323af667fSShagun Agrawal * Releases ref count and frees up an L2T entry from L2T table
1423af667fSShagun Agrawal */
cxgbe_l2t_release(struct l2t_entry * e)1523af667fSShagun Agrawal void cxgbe_l2t_release(struct l2t_entry *e)
1623af667fSShagun Agrawal {
17*e12a0166STyler Retzlaff if (rte_atomic_load_explicit(&e->refcnt, rte_memory_order_relaxed) != 0)
18*e12a0166STyler Retzlaff rte_atomic_fetch_sub_explicit(&e->refcnt, 1, rte_memory_order_relaxed);
1923af667fSShagun Agrawal }
2023af667fSShagun Agrawal
2123af667fSShagun Agrawal /**
2223af667fSShagun Agrawal * Process a CPL_L2T_WRITE_RPL. Note that the TID in the reply is really
2323af667fSShagun Agrawal * the L2T index it refers to.
2423af667fSShagun Agrawal */
cxgbe_do_l2t_write_rpl(struct adapter * adap,const struct cpl_l2t_write_rpl * rpl)2571e9b334SRahul Lakkireddy void cxgbe_do_l2t_write_rpl(struct adapter *adap,
2671e9b334SRahul Lakkireddy const struct cpl_l2t_write_rpl *rpl)
2723af667fSShagun Agrawal {
2823af667fSShagun Agrawal struct l2t_data *d = adap->l2t;
2923af667fSShagun Agrawal unsigned int tid = GET_TID(rpl);
3023af667fSShagun Agrawal unsigned int l2t_idx = tid % L2T_SIZE;
3123af667fSShagun Agrawal
3223af667fSShagun Agrawal if (unlikely(rpl->status != CPL_ERR_NONE)) {
3323af667fSShagun Agrawal dev_err(adap,
3423af667fSShagun Agrawal "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
3523af667fSShagun Agrawal rpl->status, l2t_idx);
3623af667fSShagun Agrawal return;
3723af667fSShagun Agrawal }
3823af667fSShagun Agrawal
3923af667fSShagun Agrawal if (tid & F_SYNC_WR) {
4023af667fSShagun Agrawal struct l2t_entry *e = &d->l2tab[l2t_idx - d->l2t_start];
4123af667fSShagun Agrawal
4223af667fSShagun Agrawal t4_os_lock(&e->lock);
4323af667fSShagun Agrawal if (e->state != L2T_STATE_SWITCHING)
4423af667fSShagun Agrawal e->state = L2T_STATE_VALID;
4523af667fSShagun Agrawal t4_os_unlock(&e->lock);
4623af667fSShagun Agrawal }
4723af667fSShagun Agrawal }
4823af667fSShagun Agrawal
4923af667fSShagun Agrawal /**
5023af667fSShagun Agrawal * Write an L2T entry. Must be called with the entry locked.
5123af667fSShagun Agrawal * The write may be synchronous or asynchronous.
5223af667fSShagun Agrawal */
write_l2e(struct rte_eth_dev * dev,struct l2t_entry * e,int sync,bool loopback,bool arpmiss)5323af667fSShagun Agrawal static int write_l2e(struct rte_eth_dev *dev, struct l2t_entry *e, int sync,
5423af667fSShagun Agrawal bool loopback, bool arpmiss)
5523af667fSShagun Agrawal {
5623af667fSShagun Agrawal struct adapter *adap = ethdev2adap(dev);
5723af667fSShagun Agrawal struct l2t_data *d = adap->l2t;
5823af667fSShagun Agrawal struct rte_mbuf *mbuf;
5923af667fSShagun Agrawal struct cpl_l2t_write_req *req;
6023af667fSShagun Agrawal struct sge_ctrl_txq *ctrlq;
6123af667fSShagun Agrawal unsigned int l2t_idx = e->idx + d->l2t_start;
6223af667fSShagun Agrawal unsigned int port_id = ethdev2pinfo(dev)->port_id;
6323af667fSShagun Agrawal
6423af667fSShagun Agrawal ctrlq = &adap->sge.ctrlq[port_id];
6523af667fSShagun Agrawal mbuf = rte_pktmbuf_alloc(ctrlq->mb_pool);
6623af667fSShagun Agrawal if (!mbuf)
6723af667fSShagun Agrawal return -ENOMEM;
6823af667fSShagun Agrawal
6923af667fSShagun Agrawal mbuf->data_len = sizeof(*req);
7023af667fSShagun Agrawal mbuf->pkt_len = mbuf->data_len;
7123af667fSShagun Agrawal
7223af667fSShagun Agrawal req = rte_pktmbuf_mtod(mbuf, struct cpl_l2t_write_req *);
7323af667fSShagun Agrawal INIT_TP_WR(req, 0);
7423af667fSShagun Agrawal
7523af667fSShagun Agrawal OPCODE_TID(req) =
7623af667fSShagun Agrawal cpu_to_be32(MK_OPCODE_TID(CPL_L2T_WRITE_REQ,
7723af667fSShagun Agrawal l2t_idx | V_SYNC_WR(sync) |
7823af667fSShagun Agrawal V_TID_QID(adap->sge.fw_evtq.abs_id)));
7923af667fSShagun Agrawal req->params = cpu_to_be16(V_L2T_W_PORT(e->lport) |
8023af667fSShagun Agrawal V_L2T_W_LPBK(loopback) |
8123af667fSShagun Agrawal V_L2T_W_ARPMISS(arpmiss) |
8223af667fSShagun Agrawal V_L2T_W_NOREPLY(!sync));
8323af667fSShagun Agrawal req->l2t_idx = cpu_to_be16(l2t_idx);
8423af667fSShagun Agrawal req->vlan = cpu_to_be16(e->vlan);
8535b2d13fSOlivier Matz rte_memcpy(req->dst_mac, e->dmac, RTE_ETHER_ADDR_LEN);
8623af667fSShagun Agrawal
8723af667fSShagun Agrawal if (loopback)
8835b2d13fSOlivier Matz memset(req->dst_mac, 0, RTE_ETHER_ADDR_LEN);
8923af667fSShagun Agrawal
9023af667fSShagun Agrawal t4_mgmt_tx(ctrlq, mbuf);
9123af667fSShagun Agrawal
9223af667fSShagun Agrawal if (sync && e->state != L2T_STATE_SWITCHING)
9323af667fSShagun Agrawal e->state = L2T_STATE_SYNC_WRITE;
9423af667fSShagun Agrawal
9523af667fSShagun Agrawal return 0;
9623af667fSShagun Agrawal }
9723af667fSShagun Agrawal
9823af667fSShagun Agrawal /**
9923af667fSShagun Agrawal * find_or_alloc_l2e - Find/Allocate a free L2T entry
10023af667fSShagun Agrawal * @d: L2T table
10123af667fSShagun Agrawal * @vlan: VLAN id to compare/add
10223af667fSShagun Agrawal * @port: port id to compare/add
10323af667fSShagun Agrawal * @dmac: Destination MAC address to compare/add
10423af667fSShagun Agrawal * Returns pointer to the L2T entry found/created
10523af667fSShagun Agrawal *
10623af667fSShagun Agrawal * Finds/Allocates an L2T entry to be used by switching rule of a filter.
10723af667fSShagun Agrawal */
find_or_alloc_l2e(struct l2t_data * d,u16 vlan,u8 port,u8 * dmac)10823af667fSShagun Agrawal static struct l2t_entry *find_or_alloc_l2e(struct l2t_data *d, u16 vlan,
10923af667fSShagun Agrawal u8 port, u8 *dmac)
11023af667fSShagun Agrawal {
11123af667fSShagun Agrawal struct l2t_entry *end, *e;
11223af667fSShagun Agrawal struct l2t_entry *first_free = NULL;
11323af667fSShagun Agrawal
11423af667fSShagun Agrawal for (e = &d->l2tab[0], end = &d->l2tab[d->l2t_size]; e != end; ++e) {
115*e12a0166STyler Retzlaff if (rte_atomic_load_explicit(&e->refcnt, rte_memory_order_relaxed) == 0) {
11623af667fSShagun Agrawal if (!first_free)
11723af667fSShagun Agrawal first_free = e;
11823af667fSShagun Agrawal } else {
11923af667fSShagun Agrawal if (e->state == L2T_STATE_SWITCHING) {
12035b2d13fSOlivier Matz if ((!memcmp(e->dmac, dmac, RTE_ETHER_ADDR_LEN)) &&
12123af667fSShagun Agrawal e->vlan == vlan && e->lport == port)
12223af667fSShagun Agrawal goto exists;
12323af667fSShagun Agrawal }
12423af667fSShagun Agrawal }
12523af667fSShagun Agrawal }
12623af667fSShagun Agrawal
12723af667fSShagun Agrawal if (first_free) {
12823af667fSShagun Agrawal e = first_free;
12923af667fSShagun Agrawal goto found;
13023af667fSShagun Agrawal }
13123af667fSShagun Agrawal
13223af667fSShagun Agrawal return NULL;
13323af667fSShagun Agrawal
13423af667fSShagun Agrawal found:
13523af667fSShagun Agrawal e->state = L2T_STATE_UNUSED;
13623af667fSShagun Agrawal
13723af667fSShagun Agrawal exists:
13823af667fSShagun Agrawal return e;
13923af667fSShagun Agrawal }
14023af667fSShagun Agrawal
t4_l2t_alloc_switching(struct rte_eth_dev * dev,u16 vlan,u8 port,u8 * eth_addr)14123af667fSShagun Agrawal static struct l2t_entry *t4_l2t_alloc_switching(struct rte_eth_dev *dev,
14223af667fSShagun Agrawal u16 vlan, u8 port,
14323af667fSShagun Agrawal u8 *eth_addr)
14423af667fSShagun Agrawal {
14523af667fSShagun Agrawal struct adapter *adap = ethdev2adap(dev);
14623af667fSShagun Agrawal struct l2t_data *d = adap->l2t;
14723af667fSShagun Agrawal struct l2t_entry *e;
14823af667fSShagun Agrawal int ret = 0;
14923af667fSShagun Agrawal
15023af667fSShagun Agrawal t4_os_write_lock(&d->lock);
15123af667fSShagun Agrawal e = find_or_alloc_l2e(d, vlan, port, eth_addr);
15223af667fSShagun Agrawal if (e) {
15323af667fSShagun Agrawal t4_os_lock(&e->lock);
154*e12a0166STyler Retzlaff if (rte_atomic_load_explicit(&e->refcnt, rte_memory_order_relaxed) == 0) {
15523af667fSShagun Agrawal e->state = L2T_STATE_SWITCHING;
15623af667fSShagun Agrawal e->vlan = vlan;
15723af667fSShagun Agrawal e->lport = port;
15835b2d13fSOlivier Matz rte_memcpy(e->dmac, eth_addr, RTE_ETHER_ADDR_LEN);
159*e12a0166STyler Retzlaff rte_atomic_store_explicit(&e->refcnt, 1, rte_memory_order_relaxed);
16023af667fSShagun Agrawal ret = write_l2e(dev, e, 0, !L2T_LPBK, !L2T_ARPMISS);
16123af667fSShagun Agrawal if (ret < 0)
16223af667fSShagun Agrawal dev_debug(adap, "Failed to write L2T entry: %d",
16323af667fSShagun Agrawal ret);
16423af667fSShagun Agrawal } else {
165*e12a0166STyler Retzlaff rte_atomic_fetch_add_explicit(&e->refcnt, 1, rte_memory_order_relaxed);
16623af667fSShagun Agrawal }
16723af667fSShagun Agrawal t4_os_unlock(&e->lock);
16823af667fSShagun Agrawal }
16923af667fSShagun Agrawal t4_os_write_unlock(&d->lock);
17023af667fSShagun Agrawal
17123af667fSShagun Agrawal return ret ? NULL : e;
17223af667fSShagun Agrawal }
17323af667fSShagun Agrawal
17423af667fSShagun Agrawal /**
17523af667fSShagun Agrawal * cxgbe_l2t_alloc_switching - Allocate a L2T entry for switching rule
17623af667fSShagun Agrawal * @dev: rte_eth_dev pointer
17723af667fSShagun Agrawal * @vlan: VLAN Id
17823af667fSShagun Agrawal * @port: Associated port
17923af667fSShagun Agrawal * @dmac: Destination MAC address to add to L2T
18023af667fSShagun Agrawal * Returns pointer to the allocated l2t entry
18123af667fSShagun Agrawal *
18223af667fSShagun Agrawal * Allocates a L2T entry for use by switching rule of a filter
18323af667fSShagun Agrawal */
cxgbe_l2t_alloc_switching(struct rte_eth_dev * dev,u16 vlan,u8 port,u8 * dmac)18423af667fSShagun Agrawal struct l2t_entry *cxgbe_l2t_alloc_switching(struct rte_eth_dev *dev, u16 vlan,
18523af667fSShagun Agrawal u8 port, u8 *dmac)
18623af667fSShagun Agrawal {
18723af667fSShagun Agrawal return t4_l2t_alloc_switching(dev, vlan, port, dmac);
18823af667fSShagun Agrawal }
18923af667fSShagun Agrawal
19023af667fSShagun Agrawal /**
19123af667fSShagun Agrawal * Initialize L2 Table
19223af667fSShagun Agrawal */
t4_init_l2t(unsigned int l2t_start,unsigned int l2t_end)19323af667fSShagun Agrawal struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end)
19423af667fSShagun Agrawal {
19523af667fSShagun Agrawal unsigned int l2t_size;
19623af667fSShagun Agrawal unsigned int i;
19723af667fSShagun Agrawal struct l2t_data *d;
19823af667fSShagun Agrawal
19923af667fSShagun Agrawal if (l2t_start >= l2t_end || l2t_end >= L2T_SIZE)
20023af667fSShagun Agrawal return NULL;
20123af667fSShagun Agrawal l2t_size = l2t_end - l2t_start + 1;
20223af667fSShagun Agrawal
20323af667fSShagun Agrawal d = t4_os_alloc(sizeof(*d) + l2t_size * sizeof(struct l2t_entry));
20423af667fSShagun Agrawal if (!d)
20523af667fSShagun Agrawal return NULL;
20623af667fSShagun Agrawal
20723af667fSShagun Agrawal d->l2t_start = l2t_start;
20823af667fSShagun Agrawal d->l2t_size = l2t_size;
20923af667fSShagun Agrawal
21023af667fSShagun Agrawal t4_os_rwlock_init(&d->lock);
21123af667fSShagun Agrawal
21223af667fSShagun Agrawal for (i = 0; i < d->l2t_size; ++i) {
21323af667fSShagun Agrawal d->l2tab[i].idx = i;
21423af667fSShagun Agrawal d->l2tab[i].state = L2T_STATE_UNUSED;
21523af667fSShagun Agrawal t4_os_lock_init(&d->l2tab[i].lock);
216a12f14bcSRahul Lakkireddy d->l2tab[i].refcnt = 0;
21723af667fSShagun Agrawal }
21823af667fSShagun Agrawal
21923af667fSShagun Agrawal return d;
22023af667fSShagun Agrawal }
22123af667fSShagun Agrawal
22223af667fSShagun Agrawal /**
22323af667fSShagun Agrawal * Cleanup L2 Table
22423af667fSShagun Agrawal */
t4_cleanup_l2t(struct adapter * adap)22523af667fSShagun Agrawal void t4_cleanup_l2t(struct adapter *adap)
22623af667fSShagun Agrawal {
22723af667fSShagun Agrawal if (adap->l2t)
22823af667fSShagun Agrawal t4_os_free(adap->l2t);
22923af667fSShagun Agrawal }
230