From patchwork Tue Mar 28 03:48:58 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajit Khaparde X-Patchwork-Id: 22482 X-Patchwork-Delegate: ferruh.yigit@amd.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 E2FF1D272; Tue, 28 Mar 2017 05:50:16 +0200 (CEST) Received: from rnd-relay.smtp.broadcom.com (lpdvrndsmtp01.broadcom.com [192.19.229.170]) by dpdk.org (Postfix) with ESMTP id A9E953277 for ; Tue, 28 Mar 2017 05:49:21 +0200 (CEST) Received: from mail-irv-17.broadcom.com (mail-irv-17.lvn.broadcom.net [10.75.224.233]) by rnd-relay.smtp.broadcom.com (Postfix) with ESMTP id B1EBA30CD11 for ; Mon, 27 Mar 2017 20:49:20 -0700 (PDT) Received: from C02PT1RBG8WP.vpn.broadcom.net (unknown [10.10.115.230]) by mail-irv-17.broadcom.com (Postfix) with ESMTP id 5B8F281E9A for ; Mon, 27 Mar 2017 20:49:20 -0700 (PDT) From: Ajit Khaparde To: dev@dpdk.org Date: Mon, 27 Mar 2017 22:48:58 -0500 Message-Id: <20170328034903.41482-24-ajit.khaparde@broadcom.com> X-Mailer: git-send-email 2.10.1 (Apple Git-78) In-Reply-To: <20170328034903.41482-1-ajit.khaparde@broadcom.com> References: <20170328034903.41482-1-ajit.khaparde@broadcom.com> Subject: [dpdk-dev] [PATCH 23/28] bnxt: Add support for VLAN filter and strip dev_ops 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" This patch adds VLAN strip and offload callbacks. To add a VLAN filter: For each VNIC and each associated filter(s) if VLAN exists: if VLAN matches vlan_id VLAN filter already exists, just skip and continue else add a new MAC+VLAN filter else Remove the old MAC only filter Add a new MAC+VLAN filter To remove a VLAN filter: For each VNIC and each associated filter(s) if VLAN exists && VLAN matches vlan_id remove the MAC+VLAN filter add a new MAC only filter else VLAN filter doesn't exist, just skip and continue Signed-off-by: Ajit Khaparde --- drivers/net/bnxt/bnxt_ethdev.c | 246 +++++++++++++++++++++++++++++++++++++++++ drivers/net/bnxt/bnxt_hwrm.c | 2 +- drivers/net/bnxt/bnxt_rxr.c | 2 +- 3 files changed, 248 insertions(+), 2 deletions(-) diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c index ee13ed6..641dcd4 100644 --- a/drivers/net/bnxt/bnxt_ethdev.c +++ b/drivers/net/bnxt/bnxt_ethdev.c @@ -137,6 +137,7 @@ static const struct rte_pci_id bnxt_pci_id_map[] = { ETH_RSS_NONFRAG_IPV6_TCP | \ ETH_RSS_NONFRAG_IPV6_UDP) +static void bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask); /***********************/ /* @@ -484,6 +485,7 @@ static int bnxt_dev_lsc_intr_setup(struct rte_eth_dev *eth_dev) static int bnxt_dev_start_op(struct rte_eth_dev *eth_dev) { struct bnxt *bp = (struct bnxt *)eth_dev->data->dev_private; + int vlan_mask = 0; int rc; bp->dev_stopped = 0; @@ -493,6 +495,13 @@ static int bnxt_dev_start_op(struct rte_eth_dev *eth_dev) goto error; bnxt_link_update_op(eth_dev, 0); + + if (eth_dev->data->dev_conf.rxmode.hw_vlan_filter) + vlan_mask |= ETH_VLAN_FILTER_MASK; + if (eth_dev->data->dev_conf.rxmode.hw_vlan_strip) + vlan_mask |= ETH_VLAN_STRIP_MASK; + bnxt_vlan_offload_set_op(eth_dev, vlan_mask); + return 0; error: @@ -1087,6 +1096,240 @@ bnxt_udp_tunnel_port_del_op(struct rte_eth_dev *eth_dev, return rc; } +static int bnxt_del_vlan_filter(struct bnxt *bp, uint16_t vlan_id) +{ + struct bnxt_filter_info *filter, *temp_filter, *new_filter; + struct bnxt_vnic_info *vnic; + unsigned int i; + int rc = 0; + uint32_t chk = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_OVLAN; + + /* Cycle through all VNICs */ + for (i = 0; i < bp->nr_vnics; i++) { + /* + * For each VNIC and each associated filter(s) + * if VLAN exists && VLAN matches vlan_id + * remove the MAC+VLAN filter + * add a new MAC only filter + * else + * VLAN filter doesn't exist, just skip and continue + */ + STAILQ_FOREACH(vnic, &bp->ff_pool[i], next) { + filter = STAILQ_FIRST(&vnic->filter); + while (filter) { + temp_filter = STAILQ_NEXT(filter, next); + + if (filter->enables & chk && + filter->l2_ovlan == vlan_id) { + /* Must delete the filter */ + STAILQ_REMOVE(&vnic->filter, filter, + bnxt_filter_info, next); + bnxt_hwrm_clear_filter(bp, filter); + STAILQ_INSERT_TAIL( + &bp->free_filter_list, + filter, next); + + /* + * Need to examine to see if the MAC + * filter already existed or not before + * allocating a new one + */ + + new_filter = bnxt_alloc_filter(bp); + if (!new_filter) { + RTE_LOG(ERR, PMD, + "MAC/VLAN filter alloc failed\n"); + rc = -ENOMEM; + goto exit; + } + STAILQ_INSERT_TAIL(&vnic->filter, + new_filter, next); + /* Inherit MAC from previous filter */ + new_filter->mac_index = + filter->mac_index; + memcpy(new_filter->l2_addr, + filter->l2_addr, ETHER_ADDR_LEN); + /* MAC only filter */ + rc = bnxt_hwrm_set_filter(bp, vnic, + new_filter); + if (rc) + goto exit; + RTE_LOG(INFO, PMD, + "Del Vlan filter for %d\n", + vlan_id); + } + filter = temp_filter; + } + } + } +exit: + return rc; +} + +static int bnxt_add_vlan_filter(struct bnxt *bp, uint16_t vlan_id) +{ + struct bnxt_filter_info *filter, *temp_filter, *new_filter; + struct bnxt_vnic_info *vnic; + unsigned int i; + int rc = 0; + uint32_t en = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_OVLAN | + HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_OVLAN_MASK; + uint32_t chk = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_OVLAN; + + /* Cycle through all VNICs */ + for (i = 0; i < bp->nr_vnics; i++) { + /* + * For each VNIC and each associated filter(s) + * if VLAN exists: + * if VLAN matches vlan_id + * VLAN filter already exists, just skip and continue + * else + * add a new MAC+VLAN filter + * else + * Remove the old MAC only filter + * Add a new MAC+VLAN filter + */ + STAILQ_FOREACH(vnic, &bp->ff_pool[i], next) { + filter = STAILQ_FIRST(&vnic->filter); + while (filter) { + temp_filter = STAILQ_NEXT(filter, next); + + if (filter->enables & chk) { + if (filter->l2_ovlan == vlan_id) + goto cont; + } else { + /* Must delete the MAC filter */ + STAILQ_REMOVE(&vnic->filter, filter, + bnxt_filter_info, next); + bnxt_hwrm_clear_filter(bp, filter); + filter->l2_ovlan = 0; + STAILQ_INSERT_TAIL( + &bp->free_filter_list, + filter, next); + } + new_filter = bnxt_alloc_filter(bp); + if (!new_filter) { + RTE_LOG(ERR, PMD, + "MAC/VLAN filter alloc failed\n"); + rc = -ENOMEM; + goto exit; + } + STAILQ_INSERT_TAIL(&vnic->filter, new_filter, + next); + /* Inherit MAC from the previous filter */ + new_filter->mac_index = filter->mac_index; + memcpy(new_filter->l2_addr, filter->l2_addr, + ETHER_ADDR_LEN); + /* MAC + VLAN ID filter */ + new_filter->l2_ovlan = vlan_id; + new_filter->l2_ovlan_mask = 0xF000; + new_filter->enables |= en; + rc = bnxt_hwrm_set_filter(bp, vnic, new_filter); + if (rc) + goto exit; + RTE_LOG(INFO, PMD, + "Added Vlan filter for %d\n", vlan_id); +cont: + filter = temp_filter; + } + } + } +exit: + return rc; +} + +static int bnxt_vlan_filter_set_op(struct rte_eth_dev *eth_dev, + uint16_t vlan_id, int on) +{ + struct bnxt *bp = (struct bnxt *)eth_dev->data->dev_private; + + /* These operations apply to ALL existing MAC/VLAN filters */ + if (on) + return bnxt_add_vlan_filter(bp, vlan_id); + else + return bnxt_del_vlan_filter(bp, vlan_id); +} + +static void bnxt_vlan_strip_queue_set_op(struct rte_eth_dev *eth_dev, + uint16_t rx_queue_id, int on) +{ + struct bnxt *bp = (struct bnxt *)eth_dev->data->dev_private; + struct bnxt_rx_queue *rxq = eth_dev->data->rx_queues[rx_queue_id]; + struct bnxt_vnic_info *vnic; + int rc = 0; + + /* VLAN strip at the VNIC level is supported */ + if (rxq == NULL) { + RTE_LOG(ERR, PMD, "Invalid Rx queue id %d!", rx_queue_id); + return; + } + if (rxq->vnic == NULL) { + RTE_LOG(ERR, PMD, "No VNIC associated with Rx queue id %d!", + rx_queue_id); + return; + } + + vnic = rxq->vnic; + if ((on && vnic->vlan_strip) || (!on && !vnic->vlan_strip)) { + RTE_LOG(INFO, PMD, + "Rx queue %d already has VLAN strip set to %d", + rx_queue_id, on); + return; + } + vnic->vlan_strip = on ? true : false; + rc = bnxt_hwrm_vnic_cfg(bp, vnic); + if (rc) { + RTE_LOG(ERR, PMD, "HWRM vnic cfg failure rc: %x\n", rc); + return; + } + + /* + * TODO: If there are other rx queues that belong to the same VNIC, + * we have the following options: + * 1. Accept the change and silently force the same VLAN strip + * setting to all associated rx queues [current implementation] + * 2. Migrate any rx queues that are hanging on the same VNIC to + * a new VNIC + * 3. Reject the request if there are other rx queues using the + * same VNIC + */ +} + +static void +bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask) +{ + struct bnxt *bp = (struct bnxt *)dev->data->dev_private; + unsigned int i; + + if (mask & ETH_VLAN_FILTER_MASK) { + if (!dev->data->dev_conf.rxmode.hw_vlan_filter) { + /* Remove any VLAN filters programmed */ + for (i = 0; i < 4095; i++) + bnxt_del_vlan_filter(bp, i); + } + RTE_LOG(INFO, PMD, "VLAN Filtering: %d\n", + dev->data->dev_conf.rxmode.hw_vlan_filter); + } + + if (mask & ETH_VLAN_STRIP_MASK) { + /* Enable or disable VLAN stripping */ + for (i = 0; i < bp->nr_vnics; i++) { + struct bnxt_vnic_info *vnic = &bp->vnic_info[i]; + if (dev->data->dev_conf.rxmode.hw_vlan_strip) + vnic->vlan_strip = true; + else + vnic->vlan_strip = false; + bnxt_hwrm_vnic_cfg(bp, vnic); + } + RTE_LOG(INFO, PMD, "VLAN Strip Offload: %d\n", + dev->data->dev_conf.rxmode.hw_vlan_strip); + } + + if (mask & ETH_VLAN_EXTEND_MASK) + RTE_LOG(ERR, PMD, "Extend VLAN Not supported\n"); +} + + /* * Initialization */ @@ -1120,6 +1363,9 @@ static const struct eth_dev_ops bnxt_dev_ops = { .flow_ctrl_set = bnxt_flow_ctrl_set_op, .udp_tunnel_port_add = bnxt_udp_tunnel_port_add_op, .udp_tunnel_port_del = bnxt_udp_tunnel_port_del_op, + .vlan_filter_set = bnxt_vlan_filter_set_op, + .vlan_strip_queue_set = bnxt_vlan_strip_queue_set_op, + .vlan_offload_set = bnxt_vlan_offload_set_op, }; static bool bnxt_vf_pciid(uint16_t id) diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c index 47f264b..dd823c3 100644 --- a/drivers/net/bnxt/bnxt_hwrm.c +++ b/drivers/net/bnxt/bnxt_hwrm.c @@ -893,7 +893,7 @@ int bnxt_hwrm_vnic_alloc(struct bnxt *bp, struct bnxt_vnic_info *vnic) int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic) { int rc = 0; - struct hwrm_vnic_cfg_input req = {.req_type = 0 }; + struct hwrm_vnic_cfg_input req = { 0 }; struct hwrm_vnic_cfg_output *resp = bp->hwrm_cmd_resp_addr; HWRM_PREP(req, VNIC_CFG, -1, resp); diff --git a/drivers/net/bnxt/bnxt_rxr.c b/drivers/net/bnxt/bnxt_rxr.c index 5d93de2..c01abe0 100644 --- a/drivers/net/bnxt/bnxt_rxr.c +++ b/drivers/net/bnxt/bnxt_rxr.c @@ -144,7 +144,7 @@ static uint16_t bnxt_rx_pkt(struct rte_mbuf **rx_pkt, (RX_PKT_CMPL_METADATA_VID_MASK | RX_PKT_CMPL_METADATA_DE | RX_PKT_CMPL_METADATA_PRI_MASK); - mbuf->ol_flags |= PKT_RX_VLAN_PKT; + mbuf->ol_flags |= PKT_RX_VLAN_PKT | PKT_RX_VLAN_STRIPPED; } rx_buf->mbuf = NULL;