SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += cxgbe_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += t4_hw.c
SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += clip_tbl.c
+SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += mps_tcam.c
SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += l2t.c
SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += t4vf_hw.c
unsigned int l2t_end; /* Layer 2 table end */
struct clip_tbl *clipt; /* CLIP table */
struct l2t_data *l2t; /* Layer 2 table */
+ struct mpstcam_table *mpstcam;
struct tid_info tids; /* Info used to access TID related tables */
};
int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
int mtu, int promisc, int all_multi, int bcast, int vlanex,
bool sleep_ok);
+int t4_free_raw_mac_filt(struct adapter *adap, unsigned int viid,
+ const u8 *addr, const u8 *mask, unsigned int idx,
+ u8 lookup_type, u8 port_id, bool sleep_ok);
+int t4_alloc_raw_mac_filt(struct adapter *adap, unsigned int viid,
+ const u8 *addr, const u8 *mask, unsigned int idx,
+ u8 lookup_type, u8 port_id, bool sleep_ok);
int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
int idx, const u8 *addr, bool persist, bool add_smt);
int t4_enable_vi_params(struct adapter *adap, unsigned int mbox,
return t4vf_wr_mbox(adap, &c, sizeof(c), NULL);
}
+/**
+ * t4_alloc_raw_mac_filt - Adds a raw mac entry in mps tcam
+ * @adap: the adapter
+ * @viid: the VI id
+ * @mac: the MAC address
+ * @mask: the mask
+ * @idx: index at which to add this entry
+ * @port_id: the port index
+ * @lookup_type: MAC address for inner (1) or outer (0) header
+ * @sleep_ok: call is allowed to sleep
+ *
+ * Adds the mac entry at the specified index using raw mac interface.
+ *
+ * Returns a negative error number or the allocated index for this mac.
+ */
+int t4_alloc_raw_mac_filt(struct adapter *adap, unsigned int viid,
+ const u8 *addr, const u8 *mask, unsigned int idx,
+ u8 lookup_type, u8 port_id, bool sleep_ok)
+{
+ int ret = 0;
+ struct fw_vi_mac_cmd c;
+ struct fw_vi_mac_raw *p = &c.u.raw;
+ u32 val;
+
+ memset(&c, 0, sizeof(c));
+ c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) |
+ F_FW_CMD_REQUEST | F_FW_CMD_WRITE |
+ V_FW_VI_MAC_CMD_VIID(viid));
+ val = V_FW_CMD_LEN16(1) |
+ V_FW_VI_MAC_CMD_ENTRY_TYPE(FW_VI_MAC_TYPE_RAW);
+ c.freemacs_to_len16 = cpu_to_be32(val);
+
+ /* Specify that this is an inner mac address */
+ p->raw_idx_pkd = cpu_to_be32(V_FW_VI_MAC_CMD_RAW_IDX(idx));
+
+ /* Lookup Type. Outer header: 0, Inner header: 1 */
+ p->data0_pkd = cpu_to_be32(V_DATALKPTYPE(lookup_type) |
+ V_DATAPORTNUM(port_id));
+ /* Lookup mask and port mask */
+ p->data0m_pkd = cpu_to_be64(V_DATALKPTYPE(M_DATALKPTYPE) |
+ V_DATAPORTNUM(M_DATAPORTNUM));
+
+ /* Copy the address and the mask */
+ memcpy((u8 *)&p->data1[0] + 2, addr, ETHER_ADDR_LEN);
+ memcpy((u8 *)&p->data1m[0] + 2, mask, ETHER_ADDR_LEN);
+
+ ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok);
+ if (ret == 0) {
+ ret = G_FW_VI_MAC_CMD_RAW_IDX(be32_to_cpu(p->raw_idx_pkd));
+ if (ret != (int)idx)
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+/**
+ * t4_free_raw_mac_filt - Frees a raw mac entry in mps tcam
+ * @adap: the adapter
+ * @viid: the VI id
+ * @addr: the MAC address
+ * @mask: the mask
+ * @idx: index of the entry in mps tcam
+ * @lookup_type: MAC address for inner (1) or outer (0) header
+ * @port_id: the port index
+ * @sleep_ok: call is allowed to sleep
+ *
+ * Removes the mac entry at the specified index using raw mac interface.
+ *
+ * Returns a negative error number on failure.
+ */
+int t4_free_raw_mac_filt(struct adapter *adap, unsigned int viid,
+ const u8 *addr, const u8 *mask, unsigned int idx,
+ u8 lookup_type, u8 port_id, bool sleep_ok)
+{
+ struct fw_vi_mac_cmd c;
+ struct fw_vi_mac_raw *p = &c.u.raw;
+ u32 raw;
+
+ memset(&c, 0, sizeof(c));
+ c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) |
+ F_FW_CMD_REQUEST | F_FW_CMD_WRITE |
+ V_FW_CMD_EXEC(0) |
+ V_FW_VI_MAC_CMD_VIID(viid));
+ raw = V_FW_VI_MAC_CMD_ENTRY_TYPE(FW_VI_MAC_TYPE_RAW);
+ c.freemacs_to_len16 = cpu_to_be32(V_FW_VI_MAC_CMD_FREEMACS(0) |
+ raw |
+ V_FW_CMD_LEN16(1));
+
+ p->raw_idx_pkd = cpu_to_be32(V_FW_VI_MAC_CMD_RAW_IDX(idx) |
+ FW_VI_MAC_ID_BASED_FREE);
+
+ /* Lookup Type. Outer header: 0, Inner header: 1 */
+ p->data0_pkd = cpu_to_be32(V_DATALKPTYPE(lookup_type) |
+ V_DATAPORTNUM(port_id));
+ /* Lookup mask and port mask */
+ p->data0m_pkd = cpu_to_be64(V_DATALKPTYPE(M_DATALKPTYPE) |
+ V_DATAPORTNUM(M_DATAPORTNUM));
+
+ /* Copy the address and the mask */
+ memcpy((u8 *)&p->data1[0] + 2, addr, ETHER_ADDR_LEN);
+ memcpy((u8 *)&p->data1m[0] + 2, mask, ETHER_ADDR_LEN);
+
+ return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok);
+}
+
/**
* t4_change_mac - modifies the exact-match filter for a MAC address
* @adap: the adapter
#define MPS_T5_CLS_SRAM_H(idx) (A_MPS_T5_CLS_SRAM_H + (idx) * 8)
#define NUM_MPS_T5_CLS_SRAM_H_INSTANCES 512
+#define S_DATAPORTNUM 12
+#define M_DATAPORTNUM 0xfU
+#define V_DATAPORTNUM(x) ((x) << S_DATAPORTNUM)
+
+#define S_DATALKPTYPE 10
+#define M_DATALKPTYPE 0x3U
+#define V_DATALKPTYPE(x) ((x) << S_DATALKPTYPE)
+
/* registers for module SGE */
#define SGE_BASE_ADDR 0x1000
/* Special VI_MAC command index ids */
#define FW_VI_MAC_ADD_MAC 0x3FF
#define FW_VI_MAC_ADD_PERSIST_MAC 0x3FE
+#define FW_VI_MAC_ID_BASED_FREE 0x3FC
enum fw_vi_mac_smac {
FW_VI_MAC_MPS_TCAM_ENTRY,
FW_VI_MAC_SMT_AND_MPSTCAM
};
+enum fw_vi_mac_entry_types {
+ FW_VI_MAC_TYPE_RAW = 0x2,
+};
+
struct fw_vi_mac_cmd {
__be32 op_to_viid;
__be32 freemacs_to_len16;
struct fw_vi_mac_hash {
__be64 hashvec;
} hash;
+ struct fw_vi_mac_raw {
+ __be32 raw_idx_pkd;
+ __be32 data0_pkd;
+ __be32 data1[2];
+ __be64 data0m_pkd;
+ __be32 data1m[2];
+ } raw;
} u;
};
#define G_FW_VI_MAC_CMD_VIID(x) \
(((x) >> S_FW_VI_MAC_CMD_VIID) & M_FW_VI_MAC_CMD_VIID)
+#define S_FW_VI_MAC_CMD_FREEMACS 31
+#define V_FW_VI_MAC_CMD_FREEMACS(x) ((x) << S_FW_VI_MAC_CMD_FREEMACS)
+
+#define S_FW_VI_MAC_CMD_ENTRY_TYPE 23
+#define V_FW_VI_MAC_CMD_ENTRY_TYPE(x) ((x) << S_FW_VI_MAC_CMD_ENTRY_TYPE)
+
#define S_FW_VI_MAC_CMD_VALID 15
#define M_FW_VI_MAC_CMD_VALID 0x1
#define V_FW_VI_MAC_CMD_VALID(x) ((x) << S_FW_VI_MAC_CMD_VALID)
#define G_FW_VI_MAC_CMD_IDX(x) \
(((x) >> S_FW_VI_MAC_CMD_IDX) & M_FW_VI_MAC_CMD_IDX)
+#define S_FW_VI_MAC_CMD_RAW_IDX 16
+#define M_FW_VI_MAC_CMD_RAW_IDX 0xffff
+#define V_FW_VI_MAC_CMD_RAW_IDX(x) ((x) << S_FW_VI_MAC_CMD_RAW_IDX)
+#define G_FW_VI_MAC_CMD_RAW_IDX(x) \
+ (((x) >> S_FW_VI_MAC_CMD_RAW_IDX) & M_FW_VI_MAC_CMD_RAW_IDX)
+
struct fw_vi_rxmode_cmd {
__be32 op_to_viid;
__be32 retval_len16;
#include "cxgbe.h"
#include "clip_tbl.h"
#include "l2t.h"
+#include "mps_tcam.h"
/**
* Allocate a chunk of memory. The allocated memory is cleared.
if (adapter->flags & FULL_INIT_DONE) {
tid_free(&adapter->tids);
+ t4_cleanup_mpstcam(adapter);
t4_cleanup_clip_tbl(adapter);
t4_cleanup_l2t(adapter);
if (is_pf4(adapter))
"filter support disabled. Continuing\n");
}
+ adapter->mpstcam = t4_init_mpstcam(adapter);
+ if (!adapter->mpstcam)
+ dev_warn(adapter, "could not allocate mps tcam table."
+ " Continuing\n");
+
if (is_hashfilter(adapter)) {
if (t4_read_reg(adapter, A_LE_DB_CONFIG) & F_HASHEN) {
u32 hash_base, hash_reg;
'cxgbe_filter.c',
'cxgbe_flow.c',
'clip_tbl.c',
+ 'mps_tcam.c',
'l2t.c',
'base/t4_hw.c',
'base/t4vf_hw.c')
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Chelsio Communications.
+ * All rights reserved.
+ */
+
+#include "mps_tcam.h"
+
+static inline bool
+match_entry(struct mps_tcam_entry *entry, const u8 *eth_addr, const u8 *mask)
+{
+ if (!memcmp(eth_addr, entry->eth_addr, ETHER_ADDR_LEN) &&
+ !memcmp(mask, entry->mask, ETHER_ADDR_LEN))
+ return true;
+ return false;
+}
+
+static int cxgbe_update_free_idx(struct mpstcam_table *t)
+{
+ struct mps_tcam_entry *entry = t->entry;
+ u16 i, next = t->free_idx + 1;
+
+ if (entry[t->free_idx].state == MPS_ENTRY_UNUSED)
+ /* You are already pointing to a free entry !! */
+ return 0;
+
+ /* loop, till we don't rollback to same index where we started */
+ for (i = next; i != t->free_idx; i++) {
+ if (i == t->size)
+ /* rollback and search free entry from start */
+ i = 0;
+
+ if (entry[i].state == MPS_ENTRY_UNUSED) {
+ t->free_idx = i;
+ return 0;
+ }
+ }
+
+ return -1; /* table is full */
+}
+
+static struct mps_tcam_entry *
+cxgbe_mpstcam_lookup(struct mpstcam_table *t, const u8 *eth_addr,
+ const u8 *mask)
+{
+ struct mps_tcam_entry *entry = t->entry;
+ int i;
+
+ if (!entry)
+ return NULL;
+
+ for (i = 0; i < t->size; i++) {
+ if (entry[i].state == MPS_ENTRY_UNUSED)
+ continue; /* entry is not being used */
+ if (match_entry(&entry[i], eth_addr, mask))
+ return &entry[i];
+ }
+
+ return NULL;
+}
+
+int cxgbe_mpstcam_alloc(struct port_info *pi, const u8 *eth_addr,
+ const u8 *mask)
+{
+ struct adapter *adap = pi->adapter;
+ struct mpstcam_table *mpstcam = adap->mpstcam;
+ struct mps_tcam_entry *entry;
+ int ret;
+
+ if (!adap->mpstcam) {
+ dev_err(adap, "mpstcam table is not available\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* If entry already present, return it. */
+ t4_os_write_lock(&mpstcam->lock);
+ entry = cxgbe_mpstcam_lookup(adap->mpstcam, eth_addr, mask);
+ if (entry) {
+ rte_atomic32_add(&entry->refcnt, 1);
+ t4_os_write_unlock(&mpstcam->lock);
+ return entry->idx;
+ }
+
+ if (mpstcam->full) {
+ t4_os_write_unlock(&mpstcam->lock);
+ dev_err(adap, "mps-tcam table is full\n");
+ return -ENOMEM;
+ }
+
+ ret = t4_alloc_raw_mac_filt(adap, pi->viid, eth_addr, mask,
+ mpstcam->free_idx, 0, pi->port_id, false);
+ if (ret <= 0) {
+ t4_os_write_unlock(&mpstcam->lock);
+ return ret;
+ }
+
+ /* Fill in the new values */
+ entry = &mpstcam->entry[ret];
+ memcpy(entry->eth_addr, eth_addr, ETHER_ADDR_LEN);
+ memcpy(entry->mask, mask, ETHER_ADDR_LEN);
+ rte_atomic32_set(&entry->refcnt, 1);
+ entry->state = MPS_ENTRY_USED;
+
+ if (cxgbe_update_free_idx(mpstcam))
+ mpstcam->full = true;
+
+ t4_os_write_unlock(&mpstcam->lock);
+ return ret;
+}
+
+int cxgbe_mpstcam_modify(struct port_info *pi, int idx, const u8 *addr)
+{
+ struct adapter *adap = pi->adapter;
+ struct mpstcam_table *mpstcam = adap->mpstcam;
+ struct mps_tcam_entry *entry;
+
+ if (!mpstcam)
+ return -EOPNOTSUPP;
+ t4_os_write_lock(&mpstcam->lock);
+ if (idx != -1 && idx >= mpstcam->size) {
+ t4_os_write_unlock(&mpstcam->lock);
+ return -EINVAL;
+ }
+ if (idx >= 0) {
+ entry = &mpstcam->entry[idx];
+ /* user wants to modify an existing entry.
+ * verify if entry exists
+ */
+ if (entry->state != MPS_ENTRY_USED) {
+ t4_os_write_unlock(&mpstcam->lock);
+ return -EINVAL;
+ }
+ }
+
+ idx = t4_change_mac(adap, adap->mbox, pi->viid, idx, addr, true, true);
+ if (idx < 0) {
+ t4_os_write_unlock(&mpstcam->lock);
+ return idx;
+ }
+
+ /* idx can now be different from what user provided */
+ entry = &mpstcam->entry[idx];
+ memcpy(entry->eth_addr, addr, ETHER_ADDR_LEN);
+ /* NOTE: we have considered the case that idx returned by t4_change_mac
+ * will be different from the user provided value only if user
+ * provided value is -1
+ */
+ if (entry->state == MPS_ENTRY_UNUSED) {
+ rte_atomic32_set(&entry->refcnt, 1);
+ entry->state = MPS_ENTRY_USED;
+ }
+
+ if (cxgbe_update_free_idx(mpstcam))
+ mpstcam->full = true;
+
+ t4_os_write_unlock(&mpstcam->lock);
+ return idx;
+}
+
+/**
+ * hold appropriate locks while calling this.
+ */
+static inline void reset_mpstcam_entry(struct mps_tcam_entry *entry)
+{
+ memset(entry->eth_addr, 0, ETHER_ADDR_LEN);
+ memset(entry->mask, 0, ETHER_ADDR_LEN);
+ rte_atomic32_clear(&entry->refcnt);
+ entry->state = MPS_ENTRY_UNUSED;
+}
+
+/**
+ * ret < 0: fatal error
+ * ret = 0: entry removed in h/w
+ * ret > 0: updated refcount.
+ */
+int cxgbe_mpstcam_remove(struct port_info *pi, u16 idx)
+{
+ struct adapter *adap = pi->adapter;
+ struct mpstcam_table *t = adap->mpstcam;
+ struct mps_tcam_entry *entry;
+ int ret;
+
+ if (!t)
+ return -EOPNOTSUPP;
+ t4_os_write_lock(&t->lock);
+ entry = &t->entry[idx];
+ if (entry->state == MPS_ENTRY_UNUSED) {
+ t4_os_write_unlock(&t->lock);
+ return -EINVAL;
+ }
+
+ if (rte_atomic32_read(&entry->refcnt) == 1)
+ ret = t4_free_raw_mac_filt(adap, pi->viid, entry->eth_addr,
+ entry->mask, idx, 1, pi->port_id,
+ false);
+ else
+ ret = rte_atomic32_sub_return(&entry->refcnt, 1);
+
+ if (ret == 0) {
+ reset_mpstcam_entry(entry);
+ t->full = false; /* We have atleast 1 free entry */
+ cxgbe_update_free_idx(t);
+ }
+
+ t4_os_write_unlock(&t->lock);
+ return ret;
+}
+
+struct mpstcam_table *t4_init_mpstcam(struct adapter *adap)
+{
+ struct mpstcam_table *t;
+ int i;
+ u16 size = adap->params.arch.mps_tcam_size;
+
+ t = t4_os_alloc(sizeof(*t) + size * sizeof(struct mps_tcam_entry));
+ if (!t)
+ return NULL;
+
+ t4_os_rwlock_init(&t->lock);
+ t->full = false;
+ t->size = size;
+
+ for (i = 0; i < size; i++) {
+ reset_mpstcam_entry(&t->entry[i]);
+ t->entry[i].mpstcam = t;
+ t->entry[i].idx = i;
+ }
+
+ /* first entry is used by chip. this is overwritten only
+ * in t4_cleanup_mpstcam()
+ */
+ t->entry[0].state = MPS_ENTRY_USED;
+ t->free_idx = 1;
+
+ return t;
+}
+
+void t4_cleanup_mpstcam(struct adapter *adap)
+{
+ if (adap->mpstcam) {
+ t4_os_free(adap->mpstcam->entry);
+ t4_os_free(adap->mpstcam);
+ }
+}
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Chelsio Communications.
+ * All rights reserved.
+ */
+
+#ifndef _CXGBE_MPSTCAM_H_
+#define _CXGBE_MPSTCAM_H_
+
+#include "common.h"
+
+enum {
+ MPS_ENTRY_UNUSED, /* Keep this first so memset 0 renders
+ * the correct state. Other states can
+ * be added in future like MPS_ENTRY_BUSY
+ * to reduce contention while mboxing
+ * the request to f/w or to denote attributes
+ * for a specific entry
+ */
+ MPS_ENTRY_USED,
+};
+
+struct mps_tcam_entry {
+ u8 state;
+ u16 idx;
+
+ /* add data here which uniquely defines an entry */
+ u8 eth_addr[ETHER_ADDR_LEN];
+ u8 mask[ETHER_ADDR_LEN];
+
+ struct mpstcam_table *mpstcam; /* backptr */
+ rte_atomic32_t refcnt;
+};
+
+struct mpstcam_table {
+ u16 size;
+ rte_rwlock_t lock;
+ u16 free_idx; /* next free index */
+ bool full; /* since free index can be present
+ * anywhere in the table, size and
+ * free_idx cannot alone determine
+ * if the table is full
+ */
+ struct mps_tcam_entry entry[0];
+};
+
+struct mpstcam_table *t4_init_mpstcam(struct adapter *adap);
+void t4_cleanup_mpstcam(struct adapter *adap);
+int cxgbe_mpstcam_alloc(struct port_info *pi, const u8 *mac, const u8 *mask);
+int cxgbe_mpstcam_remove(struct port_info *pi, u16 idx);
+int cxgbe_mpstcam_modify(struct port_info *pi, int idx, const u8 *addr);
+
+#endif /* _CXGBE_MPSTCAM_H_ */