xref: /dpdk/drivers/net/cxgbe/l2t.c (revision e12a0166c80f65e35408f4715b2f3a60763c3741)
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