From patchwork Tue Oct 15 10:44:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vamsi Krishna Attunuru X-Patchwork-Id: 61256 X-Patchwork-Delegate: jerinj@marvell.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id AFEBA1E96C; Tue, 15 Oct 2019 12:44:46 +0200 (CEST) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id DF9881C1F1 for ; Tue, 15 Oct 2019 12:44:45 +0200 (CEST) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id x9FAeje8030462; Tue, 15 Oct 2019 03:44:44 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : mime-version : content-type; s=pfpt0818; bh=NbMjYWavqdYf5qcKyAb3Ha/r12beqcoWU1Li4Yxo+nc=; b=KGmojd3vK6Aicg7QHpV787Ziv1WnzrlwGlgLRnOZ/ajGqsKS2C+T8ykUMWGgA6mnOFKJ jAVQPBoSpshPpfN9h4xe8L76RLTG2IpyX20hYQcpZ2MNA+vWRMF1pWunGE/Bmt5TUcMp JFtwfyXkEYREQ6VXyFTfEQgOsbpkM7h9BRhnA+jESLG9A/W4AdwDH9h00HMWekoUM48S T4hFSW2sxbaPibjb7UPJBZgTjlTIPY3P8zFDdjVom8MxqBg+Ckco0Qj7Q6zTZregbTB8 uQueqf0GvUmipJHQR300V3l+XrJxMYnXC2xbGnJ3LBQSA3ANeLXT9eIf7ml15El4TLNS jA== Received: from sc-exch02.marvell.com ([199.233.58.182]) by mx0a-0016f401.pphosted.com with ESMTP id 2vkc6ra5mg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Tue, 15 Oct 2019 03:44:44 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH02.marvell.com (10.93.176.82) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Tue, 15 Oct 2019 03:44:43 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Tue, 15 Oct 2019 03:44:43 -0700 Received: from hyd1vattunuru-dt.caveonetworks.com (unknown [10.29.52.72]) by maili.marvell.com (Postfix) with ESMTP id 57C3D3F703F; Tue, 15 Oct 2019 03:44:41 -0700 (PDT) From: To: CC: , , Vamsi Attunuru Date: Tue, 15 Oct 2019 16:14:21 +0530 Message-ID: <20191015104421.6269-1-vattunuru@marvell.com> X-Mailer: git-send-email 2.8.4 MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.95,1.0.8 definitions=2019-10-15_05:2019-10-15,2019-10-15 signatures=0 Subject: [dpdk-dev] [PATCH v1 1/1] net/octeontx2: add multicast filter support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Vamsi Attunuru Patch adds mc filter support for otx2 eth devices. Signed-off-by: Vamsi Attunuru Acked-by: Jerin Jacob --- doc/guides/nics/features/octeontx2.ini | 1 + doc/guides/nics/features/octeontx2_vec.ini | 1 + doc/guides/nics/octeontx2.rst | 6 + drivers/net/octeontx2/Makefile | 1 + drivers/net/octeontx2/meson.build | 1 + drivers/net/octeontx2/otx2_ethdev.c | 17 +- drivers/net/octeontx2/otx2_ethdev.h | 19 ++ drivers/net/octeontx2/otx2_mcast.c | 339 +++++++++++++++++++++++++++++ 8 files changed, 384 insertions(+), 1 deletion(-) diff --git a/doc/guides/nics/features/octeontx2.ini b/doc/guides/nics/features/octeontx2.ini index 02073be..7c59b43 100644 --- a/doc/guides/nics/features/octeontx2.ini +++ b/doc/guides/nics/features/octeontx2.ini @@ -21,6 +21,7 @@ TSO = Y Promiscuous mode = Y Allmulticast mode = Y Unicast MAC filter = Y +Multicast MAC filter = Y RSS hash = Y RSS key update = Y RSS reta update = Y diff --git a/doc/guides/nics/features/octeontx2_vec.ini b/doc/guides/nics/features/octeontx2_vec.ini index 733bb67..2553105 100644 --- a/doc/guides/nics/features/octeontx2_vec.ini +++ b/doc/guides/nics/features/octeontx2_vec.ini @@ -19,6 +19,7 @@ MTU update = Y Promiscuous mode = Y Allmulticast mode = Y Unicast MAC filter = Y +Multicast MAC filter = Y RSS hash = Y RSS key update = Y RSS reta update = Y diff --git a/doc/guides/nics/octeontx2.rst b/doc/guides/nics/octeontx2.rst index 9a76567..3b567a5 100644 --- a/doc/guides/nics/octeontx2.rst +++ b/doc/guides/nics/octeontx2.rst @@ -24,6 +24,7 @@ Features of the OCTEON TX2 Ethdev PMD are: - Multiple queues for TX and RX - Receiver Side Scaling (RSS) - MAC/VLAN filtering +- Multicast MAC filtering - Generic flow API - Inner and Outer Checksum offload - VLAN/QinQ stripping and insertion @@ -193,6 +194,11 @@ CRC striping The OCTEON TX2 SoC family NICs strip the CRC for every packet being received by the host interface irrespective of the offload configuration. +Multicast MAC filtering +~~~~~~~~~~~~~~~~~~~~~~~ + +``net_octeontx2`` pmd supports multicast mac filtering feature only on physical +function devices. Debugging Options ----------------- diff --git a/drivers/net/octeontx2/Makefile b/drivers/net/octeontx2/Makefile index 66cb5f2..0bfceca 100644 --- a/drivers/net/octeontx2/Makefile +++ b/drivers/net/octeontx2/Makefile @@ -44,6 +44,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_OCTEONTX2_PMD) += \ otx2_link.c \ otx2_vlan.c \ otx2_stats.c \ + otx2_mcast.c \ otx2_lookup.c \ otx2_ethdev.c \ otx2_flow_ctrl.c \ diff --git a/drivers/net/octeontx2/meson.build b/drivers/net/octeontx2/meson.build index 94bf09a..fad3076 100644 --- a/drivers/net/octeontx2/meson.build +++ b/drivers/net/octeontx2/meson.build @@ -12,6 +12,7 @@ sources = files('otx2_rx.c', 'otx2_link.c', 'otx2_vlan.c', 'otx2_stats.c', + 'otx2_mcast.c', 'otx2_lookup.c', 'otx2_ethdev.c', 'otx2_flow_ctrl.c', diff --git a/drivers/net/octeontx2/otx2_ethdev.c b/drivers/net/octeontx2/otx2_ethdev.c index 4a60f9f..62291c6 100644 --- a/drivers/net/octeontx2/otx2_ethdev.c +++ b/drivers/net/octeontx2/otx2_ethdev.c @@ -1583,6 +1583,7 @@ otx2_nix_configure(struct rte_eth_dev *eth_dev) if (dev->configured == 1) { otx2_nix_rxchan_bpid_cfg(eth_dev, false); otx2_nix_vlan_fini(eth_dev); + otx2_nix_mc_addr_list_uninstall(eth_dev); otx2_flow_free_all_resources(dev); oxt2_nix_unregister_queue_irqs(eth_dev); if (eth_dev->data->dev_conf.intr_conf.rxq) @@ -1678,6 +1679,12 @@ otx2_nix_configure(struct rte_eth_dev *eth_dev) goto q_irq_fini; } + rc = otx2_nix_mc_addr_list_install(eth_dev); + if (rc < 0) { + otx2_err("Failed to install mc address list rc=%d", rc); + goto cq_fini; + } + /* * Restore queue config when reconfigure followed by * reconfigure and no queue configure invoked from application case. @@ -1685,7 +1692,7 @@ otx2_nix_configure(struct rte_eth_dev *eth_dev) if (dev->configured == 1) { rc = nix_restore_queue_cfg(eth_dev); if (rc) - goto cq_fini; + goto uninstall_mc_list; } /* Update the mac address */ @@ -1709,6 +1716,8 @@ otx2_nix_configure(struct rte_eth_dev *eth_dev) dev->configured_nb_tx_qs = data->nb_tx_queues; return 0; +uninstall_mc_list: + otx2_nix_mc_addr_list_uninstall(eth_dev); cq_fini: oxt2_nix_unregister_cq_irqs(eth_dev); q_irq_fini: @@ -1952,6 +1961,7 @@ static const struct eth_dev_ops otx2_eth_dev_ops = { .mac_addr_add = otx2_nix_mac_addr_add, .mac_addr_remove = otx2_nix_mac_addr_del, .mac_addr_set = otx2_nix_mac_addr_set, + .set_mc_addr_list = otx2_nix_set_mc_addr_list, .promiscuous_enable = otx2_nix_promisc_enable, .promiscuous_disable = otx2_nix_promisc_disable, .allmulticast_enable = otx2_nix_allmulticast_enable, @@ -2169,6 +2179,8 @@ otx2_eth_dev_init(struct rte_eth_dev *eth_dev) if (rc) goto free_mac_addrs; + otx2_nix_mc_filter_init(dev); + otx2_nix_dbg("Port=%d pf=%d vf=%d ver=%s msix_off=%d hwcap=0x%" PRIx64 " rxoffload_capa=0x%" PRIx64 " txoffload_capa=0x%" PRIx64, eth_dev->data->port_id, dev->pf, dev->vf, @@ -2216,6 +2228,9 @@ otx2_eth_dev_uninit(struct rte_eth_dev *eth_dev, bool mbox_close) /* Disable other rte_flow entries */ otx2_flow_fini(dev); + /* Free multicast filter list */ + otx2_nix_mc_filter_fini(dev); + /* Disable PTP if already enabled */ if (otx2_ethdev_is_ptp_en(dev)) otx2_nix_timesync_disable(eth_dev); diff --git a/drivers/net/octeontx2/otx2_ethdev.h b/drivers/net/octeontx2/otx2_ethdev.h index 33fa0c6..4d9ed48 100644 --- a/drivers/net/octeontx2/otx2_ethdev.h +++ b/drivers/net/octeontx2/otx2_ethdev.h @@ -207,6 +207,14 @@ struct vlan_mkex_info { uint64_t lb_lt_offset; }; +struct mcast_entry { + struct rte_ether_addr mcast_mac; + uint16_t mcam_index; + TAILQ_ENTRY(mcast_entry) next; +}; + +TAILQ_HEAD(otx2_nix_mc_filter_tbl, mcast_entry); + struct vlan_entry { uint32_t mcam_idx; uint16_t vlan_id; @@ -311,6 +319,8 @@ struct otx2_eth_dev { struct rte_timecounter tx_tstamp_tc; double clk_freq_mult; uint64_t clk_delta; + bool mc_tbl_set; + struct otx2_nix_mc_filter_tbl mc_fltr_tbl; } __rte_cache_aligned; struct otx2_eth_txq { @@ -393,6 +403,15 @@ int otx2_nix_tx_queue_start(struct rte_eth_dev *eth_dev, uint16_t qidx); int otx2_nix_tx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t qidx); uint64_t otx2_nix_rxq_mbuf_setup(struct otx2_eth_dev *dev, uint16_t port_id); +/* Multicast filter APIs */ +void otx2_nix_mc_filter_init(struct otx2_eth_dev *dev); +void otx2_nix_mc_filter_fini(struct otx2_eth_dev *dev); +int otx2_nix_mc_addr_list_install(struct rte_eth_dev *eth_dev); +int otx2_nix_mc_addr_list_uninstall(struct rte_eth_dev *eth_dev); +int otx2_nix_set_mc_addr_list(struct rte_eth_dev *eth_dev, + struct rte_ether_addr *mc_addr_set, + uint32_t nb_mc_addr); + /* MTU */ int otx2_nix_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu); int otx2_nix_recalc_mtu(struct rte_eth_dev *eth_dev); diff --git a/drivers/net/octeontx2/otx2_mcast.c b/drivers/net/octeontx2/otx2_mcast.c new file mode 100644 index 0000000..f84aa1b --- /dev/null +++ b/drivers/net/octeontx2/otx2_mcast.c @@ -0,0 +1,339 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2019 Marvell International Ltd. + */ + +#include "otx2_ethdev.h" + +static int +nix_mc_addr_list_free(struct otx2_eth_dev *dev, uint32_t entry_count) +{ + struct npc_mcam_free_entry_req *req; + struct otx2_mbox *mbox = dev->mbox; + struct mcast_entry *entry; + int rc = 0; + + if (entry_count == 0) + goto exit; + + TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) { + req = otx2_mbox_alloc_msg_npc_mcam_free_entry(mbox); + req->entry = entry->mcam_index; + + rc = otx2_mbox_process_msg(mbox, NULL); + if (rc < 0) + goto exit; + + TAILQ_REMOVE(&dev->mc_fltr_tbl, entry, next); + rte_free(entry); + entry_count--; + + if (entry_count == 0) + break; + } + + if (entry == NULL) + dev->mc_tbl_set = false; + +exit: + return rc; +} + +static int +nix_hw_update_mc_addr_list(struct rte_eth_dev *eth_dev) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + struct otx2_npc_flow_info *npc = &dev->npc_flow; + volatile uint8_t *key_data, *key_mask; + struct npc_mcam_write_entry_req *req; + struct otx2_mbox *mbox = dev->mbox; + struct npc_xtract_info *x_info; + uint64_t mcam_data, mcam_mask; + struct mcast_entry *entry; + otx2_dxcfg_t *ld_cfg; + uint8_t *mac_addr; + uint64_t action; + int idx, rc = 0; + + ld_cfg = &npc->prx_dxcfg; + /* Get ETH layer profile info for populating mcam entries */ + x_info = &(*ld_cfg)[NPC_MCAM_RX][NPC_LID_LA][NPC_LT_LA_ETHER].xtract[0]; + + TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) { + req = otx2_mbox_alloc_msg_npc_mcam_write_entry(mbox); + if (req == NULL) { + /* The mbox memory buffer can be full. + * Flush it and retry + */ + otx2_mbox_msg_send(mbox, 0); + rc = otx2_mbox_wait_for_rsp(mbox, 0); + if (rc < 0) + goto exit; + + req = otx2_mbox_alloc_msg_npc_mcam_write_entry(mbox); + if (req == NULL) { + rc = -ENOMEM; + goto exit; + } + } + req->entry = entry->mcam_index; + req->intf = NPC_MCAM_RX; + req->enable_entry = 1; + + /* Channel base extracted to KW0[11:0] */ + req->entry_data.kw[0] = dev->rx_chan_base; + req->entry_data.kw_mask[0] = RTE_LEN2MASK(12, uint64_t); + + /* Update mcam address */ + key_data = (volatile uint8_t *)req->entry_data.kw; + key_mask = (volatile uint8_t *)req->entry_data.kw_mask; + + mcam_data = 0ull; + mcam_mask = RTE_LEN2MASK(48, uint64_t); + mac_addr = &entry->mcast_mac.addr_bytes[0]; + for (idx = RTE_ETHER_ADDR_LEN - 1; idx >= 0; idx--) + mcam_data |= ((uint64_t)*mac_addr++) << (8 * idx); + + otx2_mbox_memcpy(key_data + x_info->key_off, + &mcam_data, x_info->len); + otx2_mbox_memcpy(key_mask + x_info->key_off, + &mcam_mask, x_info->len); + + action = NIX_RX_ACTIONOP_UCAST; + + if (eth_dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_RSS) { + action = NIX_RX_ACTIONOP_RSS; + action |= (uint64_t)(dev->rss_info.alg_idx) << 56; + } + + action |= ((uint64_t)otx2_pfvf_func(dev->pf, dev->vf)) << 4; + req->entry_data.action = action; + } + + otx2_mbox_msg_send(mbox, 0); + rc = otx2_mbox_wait_for_rsp(mbox, 0); + +exit: + return rc; +} + +int +otx2_nix_mc_addr_list_install(struct rte_eth_dev *eth_dev) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + struct npc_mcam_alloc_entry_req *req; + struct npc_mcam_alloc_entry_rsp *rsp; + struct otx2_mbox *mbox = dev->mbox; + uint32_t entry_count = 0, idx = 0; + struct mcast_entry *entry; + int rc = 0; + + if (!dev->mc_tbl_set) + return 0; + + TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) + entry_count++; + + req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(mbox); + req->priority = NPC_MCAM_ANY_PRIO; + req->count = entry_count; + + rc = otx2_mbox_process_msg(mbox, (void *)&rsp); + if (rc || rsp->count < entry_count) { + otx2_err("Failed to allocate required mcam entries"); + goto exit; + } + + TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) + entry->mcam_index = rsp->entry_list[idx]; + + rc = nix_hw_update_mc_addr_list(eth_dev); + +exit: + return rc; +} + +int +otx2_nix_mc_addr_list_uninstall(struct rte_eth_dev *eth_dev) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + struct npc_mcam_free_entry_req *req; + struct otx2_mbox *mbox = dev->mbox; + struct mcast_entry *entry; + int rc = 0; + + if (!dev->mc_tbl_set) + return 0; + + TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) { + req = otx2_mbox_alloc_msg_npc_mcam_free_entry(mbox); + if (req == NULL) { + otx2_mbox_msg_send(mbox, 0); + rc = otx2_mbox_wait_for_rsp(mbox, 0); + if (rc < 0) + goto exit; + + req = otx2_mbox_alloc_msg_npc_mcam_free_entry(mbox); + if (req == NULL) { + rc = -ENOMEM; + goto exit; + } + } + req->entry = entry->mcam_index; + } + + otx2_mbox_msg_send(mbox, 0); + rc = otx2_mbox_wait_for_rsp(mbox, 0); + +exit: + return rc; +} + +static int +nix_setup_mc_addr_list(struct otx2_eth_dev *dev, + struct rte_ether_addr *mc_addr_set) +{ + struct npc_mcam_ena_dis_entry_req *req; + struct otx2_mbox *mbox = dev->mbox; + struct mcast_entry *entry; + uint32_t idx = 0; + int rc = 0; + + /* Populate PMD's mcast list with given mcast mac addresses and + * disable all mcam entries pertaining to the mcast list. + */ + TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) { + rte_memcpy(&entry->mcast_mac, &mc_addr_set[idx++], + RTE_ETHER_ADDR_LEN); + + req = otx2_mbox_alloc_msg_npc_mcam_dis_entry(mbox); + if (req == NULL) { + otx2_mbox_msg_send(mbox, 0); + rc = otx2_mbox_wait_for_rsp(mbox, 0); + if (rc < 0) + goto exit; + + req = otx2_mbox_alloc_msg_npc_mcam_dis_entry(mbox); + if (req == NULL) { + rc = -ENOMEM; + goto exit; + } + } + req->entry = entry->mcam_index; + } + + otx2_mbox_msg_send(mbox, 0); + rc = otx2_mbox_wait_for_rsp(mbox, 0); + +exit: + return rc; +} + +int +otx2_nix_set_mc_addr_list(struct rte_eth_dev *eth_dev, + struct rte_ether_addr *mc_addr_set, + uint32_t nb_mc_addr) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + struct npc_mcam_alloc_entry_req *req; + struct npc_mcam_alloc_entry_rsp *rsp; + struct otx2_mbox *mbox = dev->mbox; + uint32_t idx, priv_count = 0; + struct mcast_entry *entry; + int rc = 0; + + if (otx2_dev_is_vf(dev)) + return -ENOTSUP; + + TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) + priv_count++; + + if (nb_mc_addr == 0 || mc_addr_set == NULL) { + /* Free existing list if new list is null */ + nb_mc_addr = priv_count; + goto exit; + } + + for (idx = 0; idx < nb_mc_addr; idx++) { + if (!rte_is_multicast_ether_addr(&mc_addr_set[idx])) + return -EINVAL; + } + + /* New list is bigger than the existing list, + * allocate mcam entries for the extra entries. + */ + if (nb_mc_addr > priv_count) { + req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(mbox); + req->priority = NPC_MCAM_ANY_PRIO; + req->count = nb_mc_addr - priv_count; + + rc = otx2_mbox_process_msg(mbox, (void *)&rsp); + if (rc || (rsp->count + priv_count < nb_mc_addr)) { + otx2_err("Failed to allocate required entries"); + nb_mc_addr = priv_count; + goto exit; + } + + /* Append new mcam entries to the existing mc list */ + for (idx = 0; idx < rsp->count; idx++) { + entry = rte_zmalloc("otx2_nix_mc_entry", + sizeof(struct mcast_entry), 0); + if (!entry) { + otx2_err("Failed to allocate memory"); + nb_mc_addr = priv_count; + rc = -ENOMEM; + goto exit; + } + entry->mcam_index = rsp->entry_list[idx]; + TAILQ_INSERT_HEAD(&dev->mc_fltr_tbl, entry, next); + } + } else { + /* Free the extra mcam entries if the new list is smaller + * than exiting list. + */ + nix_mc_addr_list_free(dev, priv_count - nb_mc_addr); + } + + + /* Now mc_fltr_tbl has the required number of mcam entries, + * Traverse through it and add new multicast filter table entries. + */ + rc = nix_setup_mc_addr_list(dev, mc_addr_set); + if (rc < 0) + goto exit; + + rc = nix_hw_update_mc_addr_list(eth_dev); + if (rc < 0) + goto exit; + + dev->mc_tbl_set = true; + + return 0; + +exit: + nix_mc_addr_list_free(dev, nb_mc_addr); + return rc; +} + +void +otx2_nix_mc_filter_init(struct otx2_eth_dev *dev) +{ + if (otx2_dev_is_vf(dev)) + return; + + TAILQ_INIT(&dev->mc_fltr_tbl); +} + +void +otx2_nix_mc_filter_fini(struct otx2_eth_dev *dev) +{ + struct mcast_entry *entry; + uint32_t count = 0; + + if (otx2_dev_is_vf(dev)) + return; + + TAILQ_FOREACH(entry, &dev->mc_fltr_tbl, next) + count++; + + nix_mc_addr_list_free(dev, count); +}