From patchwork Wed Feb 3 08:32:28 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rahul Lakkireddy X-Patchwork-Id: 10344 X-Patchwork-Delegate: bruce.richardson@intel.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id DA998C134; Wed, 3 Feb 2016 09:33:01 +0100 (CET) Received: from stargate3.asicdesigners.com (stargate.chelsio.com [12.32.117.8]) by dpdk.org (Postfix) with ESMTP id C96B1C134 for ; Wed, 3 Feb 2016 09:32:59 +0100 (CET) Received: from localhost (scalar.blr.asicdesigners.com [10.193.185.94]) by stargate3.asicdesigners.com (8.13.8/8.13.8) with ESMTP id u138WuJ9024910; Wed, 3 Feb 2016 00:32:57 -0800 From: Rahul Lakkireddy To: dev@dpdk.org Date: Wed, 3 Feb 2016 14:02:28 +0530 Message-Id: <086ecf907e9b4ea613aa2c6d924f4f6f3b1a2ee7.1454408702.git.rahul.lakkireddy@chelsio.com> X-Mailer: git-send-email 2.5.3 In-Reply-To: References: In-Reply-To: References: Cc: Kumar Sanghvi , Nirranjan Kirubaharan Subject: [dpdk-dev] [PATCH 07/10] cxgbe: add source mac table for switch action filter X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add Source MAC Table (SMT) that holds source mac addresses to be modified on a packet that matches a corresponding set 'switch' action filter. Signed-off-by: Rahul Lakkireddy Signed-off-by: Kumar Sanghvi --- drivers/net/cxgbe/Makefile | 1 + drivers/net/cxgbe/base/adapter.h | 1 + drivers/net/cxgbe/base/t4_msg.h | 29 +++++ drivers/net/cxgbe/cxgbe_filter.h | 2 + drivers/net/cxgbe/cxgbe_main.c | 12 ++ drivers/net/cxgbe/smt.c | 275 +++++++++++++++++++++++++++++++++++++++ drivers/net/cxgbe/smt.h | 76 +++++++++++ 7 files changed, 396 insertions(+) create mode 100644 drivers/net/cxgbe/smt.c create mode 100644 drivers/net/cxgbe/smt.h diff --git a/drivers/net/cxgbe/Makefile b/drivers/net/cxgbe/Makefile index e98e93c..f5f5828 100644 --- a/drivers/net/cxgbe/Makefile +++ b/drivers/net/cxgbe/Makefile @@ -80,6 +80,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += sge.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) += l2t.c +SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += smt.c # this lib depends upon: DEPDIRS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += lib/librte_eal lib/librte_ether diff --git a/drivers/net/cxgbe/base/adapter.h b/drivers/net/cxgbe/base/adapter.h index c29bb98..6af5c8e 100644 --- a/drivers/net/cxgbe/base/adapter.h +++ b/drivers/net/cxgbe/base/adapter.h @@ -340,6 +340,7 @@ struct adapter { unsigned int l2t_start; /* Layer 2 table start */ unsigned int l2t_end; /* Layer 2 table end */ struct l2t_data *l2t; /* Layer 2 table */ + struct smt_data *smt; /* Source MAC table */ struct tid_info tids; /* Info used to access TID related tables */ }; diff --git a/drivers/net/cxgbe/base/t4_msg.h b/drivers/net/cxgbe/base/t4_msg.h index d51edd7..6dc255b 100644 --- a/drivers/net/cxgbe/base/t4_msg.h +++ b/drivers/net/cxgbe/base/t4_msg.h @@ -36,7 +36,9 @@ enum { CPL_L2T_WRITE_REQ = 0x12, + CPL_SMT_WRITE_REQ = 0x14, CPL_L2T_WRITE_RPL = 0x23, + CPL_SMT_WRITE_RPL = 0x2E, CPL_SGE_EGR_UPDATE = 0xA5, CPL_FW4_MSG = 0xC0, CPL_FW6_MSG = 0xE0, @@ -320,6 +322,33 @@ struct cpl_l2t_write_rpl { #define V_RXF_IP6(x) ((x) << S_RXF_IP6) #define F_RXF_IP6 V_RXF_IP6(1U) +struct cpl_smt_write_req { + WR_HDR; + union opcode_tid ot; + __be32 params; + __be16 pfvf1; + __u8 src_mac1[6]; + __be16 pfvf0; + __u8 src_mac0[6]; +}; + +struct cpl_smt_write_rpl { + RSS_HDR + union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +/* cpl_smt_{read,write}_req.params fields */ +#define S_SMTW_OVLAN_IDX 16 +#define V_SMTW_OVLAN_IDX(x) ((x) << S_SMTW_OVLAN_IDX) + +#define S_SMTW_IDX 20 +#define V_SMTW_IDX(x) ((x) << S_SMTW_IDX) + +#define S_SMTW_NORPL 31 +#define V_SMTW_NORPL(x) ((x) << S_SMTW_NORPL) + /* cpl_fw*.type values */ enum { FW_TYPE_RSSCPL = 4, diff --git a/drivers/net/cxgbe/cxgbe_filter.h b/drivers/net/cxgbe/cxgbe_filter.h index 933496a..b03ccca 100644 --- a/drivers/net/cxgbe/cxgbe_filter.h +++ b/drivers/net/cxgbe/cxgbe_filter.h @@ -217,9 +217,11 @@ struct filter_entry { u32 valid:1; /* filter allocated and valid */ u32 locked:1; /* filter is administratively locked */ u32 pending:1; /* filter action is pending FW reply */ + u32 smtidx:8; /* Source MAC Table index for smac */ struct filter_ctx *ctx; /* caller's completion hook */ struct clip_entry *clipt; /* CLIP Table entry for IPv6 */ struct l2t_entry *l2t; /* Layer Two Table entry for dmac */ + struct smt_entry *smt; /* Source Mac Table entry for smac */ struct rte_eth_dev *dev; /* Port's rte eth device */ /* This will store the actual tid */ diff --git a/drivers/net/cxgbe/cxgbe_main.c b/drivers/net/cxgbe/cxgbe_main.c index 63c6318..e7d017e 100644 --- a/drivers/net/cxgbe/cxgbe_main.c +++ b/drivers/net/cxgbe/cxgbe_main.c @@ -68,6 +68,7 @@ #include "cxgbe.h" #include "clip_tbl.h" #include "l2t.h" +#include "smt.h" /** * Allocate a chunk of memory. The allocated memory is cleared. @@ -117,6 +118,10 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp, const struct cpl_fw6_msg *msg = (const void *)rsp; t4_handle_fw_rpl(q->adapter, msg->data); + } else if (opcode == CPL_SMT_WRITE_RPL) { + const struct cpl_smt_write_rpl *p = (const void *)rsp; + + do_smt_write_rpl(q->adapter, p); } else if (opcode == CPL_L2T_WRITE_RPL) { const struct cpl_l2t_write_rpl *p = (const void *)rsp; @@ -1230,6 +1235,7 @@ void cxgbe_close(struct adapter *adapter) tid_free(&adapter->tids); t4_cleanup_clip_tbl(adapter); t4_cleanup_l2t(adapter); + t4_cleanup_smt(adapter); t4_intr_disable(adapter); t4_sge_tx_monitor_stop(adapter); t4_free_sge_resources(adapter); @@ -1387,6 +1393,12 @@ allocate_mac: dev_warn(adapter, "could not allocate L2T. Continuing\n"); } + adapter->smt = t4_init_smt(); + if (!adapter->smt) { + /* We tolerate a lack of SMT, giving up some functionality */ + dev_warn(adapter, "could not allocate SMT. Continuing\n"); + } + if (tid_init(&adapter->tids) < 0) { /* Disable filtering support */ dev_warn(adapter, "could not allocate TID table, " diff --git a/drivers/net/cxgbe/smt.c b/drivers/net/cxgbe/smt.c new file mode 100644 index 0000000..639c0cf --- /dev/null +++ b/drivers/net/cxgbe/smt.c @@ -0,0 +1,275 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015-2016 Chelsio Communications. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Chelsio Communications nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "common.h" +#include "smt.h" + +static void t4_smte_free(struct smt_entry *e) +{ + t4_os_lock(&e->lock); + if (rte_atomic32_read(&e->refcnt) == 0) /* hasn't been recycled */ + e->state = SMT_STATE_UNUSED; + t4_os_unlock(&e->lock); +} + +/** + * cxgbe_smt_release - Release associated SMT entry + * @e: smt entry to release + * + * Releases ref count and frees up an smt entry from SMT table + */ +void cxgbe_smt_release(struct smt_entry *e) +{ + if (rte_atomic32_dec_and_test(&e->refcnt)) + t4_smte_free(e); +} + +/** + * do_smt_write_rpl - Process the SMT_WRITE_RPL message from FW + * @adapter: associated adapter that the port belongs to + * @rpl: SMT_WRITE_RPL message to parse and process + * + * Process the SMT_WRITE_RPL message received from the FW + */ +void do_smt_write_rpl(struct adapter *adapter, + const struct cpl_smt_write_rpl *rpl) +{ + struct smt_data *s = adapter->smt; + unsigned int smtidx = G_TID_TID(GET_TID(rpl)); + + if (unlikely(rpl->status != CPL_ERR_NONE)) { + struct smt_entry *e = &s->smtab[smtidx]; + + dev_err(adapter, + "Unexpected SMT_WRITE_RPL status %u for entry %u\n", + rpl->status, smtidx); + t4_os_lock(&e->lock); + e->state = SMT_STATE_ERROR; + t4_os_unlock(&e->lock); + return; + } +} + +/** + * write_smt_entry - Send the SMT_WRITE_REQ message to FW + * @dev: associated rte_eth_dev + * @e: SMT entry to write + * + * Send the SMT_WRITE_REQ message to the FW to add an SMT entry. Must be + * called with entry lock held. + */ +static int write_smt_entry(struct rte_eth_dev *dev, struct smt_entry *e) +{ + struct adapter *adapter = ethdev2adap(dev); + struct smt_data *s = adapter->smt; + struct sge_ctrl_txq *ctrlq; + struct cpl_smt_write_req *req; + struct rte_mbuf *mbuf; + unsigned int port_id = ethdev2pinfo(dev)->port_id; + u8 row; + + ctrlq = &adapter->sge.ctrlq[port_id]; + mbuf = rte_pktmbuf_alloc(ctrlq->mb_pool); + if (!mbuf) + return -ENOMEM; + + mbuf->data_len = sizeof(*req); + mbuf->pkt_len = mbuf->data_len; + + /* Source MAC Table (SMT) contains 256 SMAC entries + * organized in 128 rows of 2 entries each. + */ + req = rte_pktmbuf_mtod(mbuf, struct cpl_smt_write_req *); + INIT_TP_WR(req, 0); + + /* Each row contains an SMAC pair. + * LSB selects the SMAC entry within a row + */ + row = (e->idx >> 1); + if (e->idx & 1) { + req->pfvf1 = 0x0; + rte_memcpy(req->src_mac1, e->src_mac, ETHER_ADDR_LEN); + + /* fill pfvf0/src_mac0 with entry + * at prev index from smt-tab. + */ + req->pfvf0 = 0x0; + rte_memcpy(req->src_mac0, &s->smtab[e->idx - 1].src_mac, + ETHER_ADDR_LEN); + } else { + req->pfvf0 = 0x0; + rte_memcpy(req->src_mac0, e->src_mac, ETHER_ADDR_LEN); + + /* fill pfvf1/src_mac1 with entry + * at next index from smt-tab + */ + req->pfvf1 = 0x0; + rte_memcpy(req->src_mac1, s->smtab[e->idx + 1].src_mac, + ETHER_ADDR_LEN); + } + + OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, e->idx | + V_TID_QID(adapter->sge.fw_evtq.abs_id))); + req->params = cpu_to_be32(V_SMTW_NORPL(0) | V_SMTW_IDX(row) | + V_SMTW_OVLAN_IDX(0)); + + t4_mgmt_tx(ctrlq, mbuf); + + return 0; +} + +/** + * find_or_alloc_smte - Find/Allocate a free SMT entry + * @s: SMT table + * @smac: MAC address to compare/add + * Returns pointer to the SMT entry found/created + * + * Finds/Allocates an SMT entry to be used by switching rule of a filter. + */ +static struct smt_entry *find_or_alloc_smte(struct smt_data *s, u8 *smac) +{ + struct smt_entry *e, *end; + struct smt_entry *first_free = NULL; + + for (e = &s->smtab[0], end = &s->smtab[s->smt_size]; e != end; ++e) { + if (rte_atomic32_read(&e->refcnt) == 0) { + if (!first_free) + first_free = e; + } else { + if (e->state == SMT_STATE_SWITCHING) { + /* + * This entry is actually in use. See if we can + * re-use it ? + */ + if (!memcmp(e->src_mac, smac, ETHER_ADDR_LEN)) + goto found_reuse; + } + } + } + + if (first_free) { + e = first_free; + goto found; + } + + return NULL; + +found: + e->state = SMT_STATE_UNUSED; + +found_reuse: + return e; +} + +static struct smt_entry *t4_smt_alloc_switching(struct rte_eth_dev *dev, + u16 pfvf, u8 *smac) +{ + struct adapter *adap = ethdev2adap(dev); + struct smt_data *s = adap->smt; + struct smt_entry *e; + int ret; + + t4_os_write_lock(&s->lock); + e = find_or_alloc_smte(s, smac); + if (e) { + t4_os_lock(&e->lock); + if (!rte_atomic32_read(&e->refcnt)) { + e->state = SMT_STATE_SWITCHING; + e->pfvf = pfvf; + rte_memcpy(e->src_mac, smac, ETHER_ADDR_LEN); + rte_atomic32_set(&e->refcnt, 1); + ret = write_smt_entry(dev, e); + if (ret < 0) { + dev_debug(adap, "Failed to write smt entry: %d", + ret); + e = NULL; + } + } else { + rte_atomic32_inc(&e->refcnt); + } + t4_os_unlock(&e->lock); + } + t4_os_write_unlock(&s->lock); + return e; +} + +/** + * cxgbe_smt_alloc_switching - Allocate a SMT entry for switching rule + * @dev: rte_eth_dev pointer + * @smac: MAC address to add to SMT + * Returns pointer to the SMT entry created + * + * Allocates a SMT entry to be used by switching rule of a filter. + */ +struct smt_entry *cxgbe_smt_alloc_switching(struct rte_eth_dev *dev, u8 *smac) +{ + return t4_smt_alloc_switching(dev, 0x0, smac); +} + +/** + * Initialize Source MAC Table + */ +struct smt_data *t4_init_smt(void) +{ + unsigned int smt_size; + unsigned int i; + struct smt_data *s; + + smt_size = SMT_SIZE; + s = t4_os_alloc(sizeof(*s) + smt_size * sizeof(struct smt_entry)); + if (!s) + return NULL; + + s->smt_size = smt_size; + t4_os_rwlock_init(&s->lock); + + for (i = 0; i < s->smt_size; ++i) { + s->smtab[i].idx = i; + s->smtab[i].state = SMT_STATE_UNUSED; + memset(&s->smtab[i].src_mac, 0, ETHER_ADDR_LEN); + t4_os_lock_init(&s->smtab[i].lock); + rte_atomic32_init(&s->smtab[i].refcnt); + rte_atomic32_set(&s->smtab[i].refcnt, 0); + } + + return s; +} + +/** + * Cleanup Source MAC Table + */ +void t4_cleanup_smt(struct adapter *adap) +{ + if (adap->smt) + t4_os_free(adap->smt); +} diff --git a/drivers/net/cxgbe/smt.h b/drivers/net/cxgbe/smt.h new file mode 100644 index 0000000..e8eed31 --- /dev/null +++ b/drivers/net/cxgbe/smt.h @@ -0,0 +1,76 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015-2016 Chelsio Communications. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Chelsio Communications nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _CXGBE_SMT_H_ +#define _CXGBE_SMT_H_ + +#include "t4_msg.h" + +/* + * SMT related handling. + */ +enum { + SMT_STATE_SWITCHING, /* entry is being used by a switching filter */ + SMT_STATE_UNUSED, /* entry not in use */ + SMT_STATE_ERROR /* got error from FW */ +}; + +enum { + SMT_SIZE = 256 /* # of SMT entries */ +}; + +/* + * State for the corresponding entry of the HW Source MAC table. + */ +struct smt_entry { + u16 state; /* entry state */ + u16 idx; /* entry index within in-memory table */ + u16 pfvf; /* associated pfvf index */ + u8 src_mac[ETHER_ADDR_LEN]; /* source MAC address */ + rte_atomic32_t refcnt; /* entry reference count */ + rte_spinlock_t lock; /* entry lock */ +}; + +struct smt_data { + unsigned int smt_size; /* size of SMT */ + rte_rwlock_t lock; /* table rw lock */ + struct smt_entry smtab[0]; /* MUST BE LAST */ +}; + +struct smt_data *t4_init_smt(void); +void t4_cleanup_smt(struct adapter *adap); +struct smt_entry *cxgbe_smt_alloc_switching(struct rte_eth_dev *dev, u8 *smac); +void cxgbe_smt_release(struct smt_entry *e); +void do_smt_write_rpl(struct adapter *adapter, + const struct cpl_smt_write_rpl *rpl); +#endif /* _CXGBE_SMT_H_ */