Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/1056169/?format=api
{ "id": 1056169, "url": "http://patchwork.ozlabs.org/api/patches/1056169/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20190313170329.4569-1-harshitha.ramamurthy@intel.com/", "project": { "id": 46, "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api", "name": "Intel Wired Ethernet development", "link_name": "intel-wired-lan", "list_id": "intel-wired-lan.osuosl.org", "list_email": "intel-wired-lan@osuosl.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20190313170329.4569-1-harshitha.ramamurthy@intel.com>", "list_archive_url": null, "date": "2019-03-13T17:03:29", "name": "[v4] i40e: Add macvlan support on i40e", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "f8f819f11591a7b14763da5dfa9999e6440244ce", "submitter": { "id": 68642, "url": "http://patchwork.ozlabs.org/api/people/68642/?format=api", "name": "Harshitha Ramamurthy", "email": "harshitha.ramamurthy@intel.com" }, "delegate": { "id": 68, "url": "http://patchwork.ozlabs.org/api/users/68/?format=api", "username": "jtkirshe", "first_name": "Jeff", "last_name": "Kirsher", "email": "jeffrey.t.kirsher@intel.com" }, "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20190313170329.4569-1-harshitha.ramamurthy@intel.com/mbox/", "series": [ { "id": 96982, "url": "http://patchwork.ozlabs.org/api/series/96982/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=96982", "date": "2019-03-13T17:03:29", "name": "[v4] i40e: Add macvlan support on i40e", "version": 4, "mbox": "http://patchwork.ozlabs.org/series/96982/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/1056169/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/1056169/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<intel-wired-lan-bounces@osuosl.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Authentication-Results": [ "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=osuosl.org\n\t(client-ip=140.211.166.136; helo=silver.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)", "ozlabs.org;\n\tdmarc=fail (p=none dis=none) header.from=intel.com" ], "Received": [ "from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 44KJ911ZsCz9s3l\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 14 Mar 2019 04:04:19 +1100 (AEDT)", "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id BB40225C57;\n\tWed, 13 Mar 2019 17:04:17 +0000 (UTC)", "from silver.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id Sww0pGwrDcRt; Wed, 13 Mar 2019 17:04:12 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby silver.osuosl.org (Postfix) with ESMTP id D276524C8E;\n\tWed, 13 Mar 2019 17:04:12 +0000 (UTC)", "from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\tby ash.osuosl.org (Postfix) with ESMTP id E4E651BF5DA\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Mar 2019 17:04:11 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id E132E85633\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Mar 2019 17:04:11 +0000 (UTC)", "from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id VoAfWBEUCirg for <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Mar 2019 17:04:10 +0000 (UTC)", "from mga03.intel.com (mga03.intel.com [134.134.136.65])\n\tby fraxinus.osuosl.org (Postfix) with ESMTPS id 239C684D74\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Mar 2019 17:04:10 +0000 (UTC)", "from fmsmga008.fm.intel.com ([10.253.24.58])\n\tby orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t13 Mar 2019 10:04:01 -0700", "from harshitha-linux4.jf.intel.com ([10.166.17.81])\n\tby fmsmga008.fm.intel.com with ESMTP; 13 Mar 2019 10:04:01 -0700" ], "X-Virus-Scanned": [ "amavisd-new at osuosl.org", "amavisd-new at osuosl.org" ], "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6", "X-Amp-Result": "SKIPPED(no attachment in message)", "X-Amp-File-Uploaded": "False", "X-ExtLoop1": "1", "X-IronPort-AV": "E=Sophos;i=\"5.58,474,1544515200\"; d=\"scan'208\";a=\"131361481\"", "From": "Harshitha Ramamurthy <harshitha.ramamurthy@intel.com>", "To": "intel-wired-lan@lists.osuosl.org", "Date": "Wed, 13 Mar 2019 13:03:29 -0400", "Message-Id": "<20190313170329.4569-1-harshitha.ramamurthy@intel.com>", "X-Mailer": "git-send-email 2.17.1", "Subject": "[Intel-wired-lan] [PATCH v4] i40e: Add macvlan support on i40e", "X-BeenThere": "intel-wired-lan@osuosl.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>", "List-Unsubscribe": "<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>", "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>", "List-Post": "<mailto:intel-wired-lan@osuosl.org>", "List-Help": "<mailto:intel-wired-lan-request@osuosl.org?subject=help>", "List-Subscribe": "<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Errors-To": "intel-wired-lan-bounces@osuosl.org", "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>" }, "content": "This patch enables macvlan offloads for i40e. The idea is to use\nchannels as macvlan interfaces. The channels are VSIs of\ntype VMDQ. When the first macvlan is created, the maximum number of\nchannels possible are created. From then on, as a macvlan interface\nis created, a mac filter is added to these already created channels\n(VSIs).\n\nThis patch builds on top of the recent changes which move\naway from the select_queue implementation of picking the tx queue.\n\nSteps to configure macvlan offloads:\n1. sudo ethtool -K ens261f1 l2-fwd-offload on\n2. ip link add link ens261f1 name macvlan1 type macvlan\n3. sudo ip link add link ens261f1 name macvlan1 type macvlan\n4. sudo ip link set macvlan1 up\n\nSigned-off-by: Harshitha Ramamurthy <harshitha.ramamurthy@intel.com>\n---\nv4: Added code to check for a non-empty list of macvlans before deleting them\n\nv3: Renamed i40e_remove_macvlan_channels() to i40e_free_macvlan_channels()\n Fixed an indentation issue and added some comments\n Removed a code name from the commit message\n Addressed some more of Shannon's comments \n\nv2: Addressed Shannon's comments\n Added a new function to remove all macvlan VSIs\n\n drivers/net/ethernet/intel/i40e/i40e.h | 26 ++\n drivers/net/ethernet/intel/i40e/i40e_main.c | 484 +++++++++++++++++++-\n 2 files changed, 508 insertions(+), 2 deletions(-)", "diff": "diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h\nindex c4afb852cb57..c44f9f7acbb5 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e.h\n@@ -27,6 +27,7 @@\n #include <net/ip6_checksum.h>\n #include <linux/ethtool.h>\n #include <linux/if_vlan.h>\n+#include <linux/if_macvlan.h>\n #include <linux/if_bridge.h>\n #include <linux/clocksource.h>\n #include <linux/net_tstamp.h>\n@@ -413,6 +414,11 @@ struct i40e_flex_pit {\n \tu8 pit_index;\n };\n \n+struct i40e_fwd_adapter {\n+\tstruct net_device *netdev;\n+\tint bit_no;\n+};\n+\n struct i40e_channel {\n \tstruct list_head list;\n \tbool initialized;\n@@ -427,11 +433,25 @@ struct i40e_channel {\n \tstruct i40e_aqc_vsi_properties_data info;\n \n \tu64 max_tx_rate;\n+\tstruct i40e_fwd_adapter *fwd;\n \n \t/* track this channel belongs to which VSI */\n \tstruct i40e_vsi *parent_vsi;\n };\n \n+static inline bool i40e_is_channel_macvlan(struct i40e_channel *ch)\n+{\n+\treturn !!ch->fwd;\n+}\n+\n+static inline u8 *i40e_channel_mac(struct i40e_channel *ch)\n+{\n+\tif (i40e_is_channel_macvlan(ch))\n+\t\treturn ch->fwd->netdev->dev_addr;\n+\telse\n+\t\treturn NULL;\n+}\n+\n /* struct that defines the Ethernet device */\n struct i40e_pf {\n \tstruct pci_dev *pdev;\n@@ -813,6 +833,12 @@ struct i40e_vsi {\n \tstruct list_head ch_list;\n \tu16 tc_seid_map[I40E_MAX_TRAFFIC_CLASS];\n \n+\t/* macvlan fields */\n+#define I40E_MAX_MACVLANS\t128 /* Max HW capable vectors - 1 on FVL */\n+\tDECLARE_BITMAP(fwd_bitmask, I40E_MAX_MACVLANS);\n+\tstruct list_head macvlan_list;\n+\tint macvlan_cnt;\n+\n \tvoid *priv;\t/* client driver data reference. */\n \n \t/* VSI specific handlers */\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c\nindex cebb3dca804b..cadee0e3ba94 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_main.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c\n@@ -5854,8 +5854,10 @@ static int i40e_add_channel(struct i40e_pf *pf, u16 uplink_seid,\n \t\treturn -ENOENT;\n \t}\n \n-\t/* Success, update channel */\n-\tch->enabled_tc = enabled_tc;\n+\t/* Success, update channel, set enabled_tc only if the channel\n+\t * is not a macvlan\n+\t */\n+\tch->enabled_tc = !i40e_is_channel_macvlan(ch) && enabled_tc;\n \tch->seid = ctxt.seid;\n \tch->vsi_number = ctxt.vsi_number;\n \tch->stat_counter_idx = cpu_to_le16(ctxt.info.stat_counter_idx);\n@@ -6852,6 +6854,476 @@ static void i40e_vsi_set_default_tc_config(struct i40e_vsi *vsi)\n \t}\n }\n \n+/**\n+ * i40e_del_macvlan_filter\n+ * @hw: pointer to the HW structure\n+ * @seid: seid of the channel VSI\n+ * @macaddr: the mac address to apply as a filter\n+ * @aq_err: store the admin Q error\n+ *\n+ * This function deletes a mac filter on the channel VSI which serves as the\n+ * macvlan. Returns 0 on success.\n+ **/\n+static i40e_status i40e_del_macvlan_filter(struct i40e_hw *hw, u16 seid,\n+\t\t\t\t\t const u8 *macaddr, int *aq_err)\n+{\n+\tstruct i40e_aqc_remove_macvlan_element_data element;\n+\ti40e_status status;\n+\n+\tmemset(&element, 0, sizeof(element));\n+\tether_addr_copy(element.mac_addr, macaddr);\n+\telement.vlan_tag = 0;\n+\telement.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;\n+\tstatus = i40e_aq_remove_macvlan(hw, seid, &element, 1, NULL);\n+\t*aq_err = hw->aq.asq_last_status;\n+\treturn status;\n+}\n+\n+/**\n+ * i40e_add_macvlan_filter\n+ * @hw: pointer to the HW structure\n+ * @seid: seid of the channel VSI\n+ * @macaddr: the mac address to apply as a filter\n+ * @aq_err: store the admin Q error\n+ *\n+ * This function adds a mac filter on the channel VSI which serves as the\n+ * macvlan. Returns 0 on success.\n+ **/\n+static i40e_status i40e_add_macvlan_filter(struct i40e_hw *hw, u16 seid,\n+\t\t\t\t\t const u8 *macaddr, int *aq_err)\n+{\n+\tstruct i40e_aqc_add_macvlan_element_data element;\n+\ti40e_status status;\n+\tu16 cmd_flags = 0;\n+\n+\tether_addr_copy(element.mac_addr, macaddr);\n+\telement.vlan_tag = 0;\n+\telement.queue_number = 0;\n+\telement.match_method = I40E_AQC_MM_ERR_NO_RES;\n+\tcmd_flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;\n+\telement.flags = cpu_to_le16(cmd_flags);\n+\tstatus = i40e_aq_add_macvlan(hw, seid, &element, 1, NULL);\n+\t*aq_err = hw->aq.asq_last_status;\n+\treturn status;\n+}\n+\n+/**\n+ * i40e_reset_ch_rings - Reset the queue contexts in a channel\n+ * @vsi: the VSI we want to access\n+ * @ch: the channel we want to access\n+ */\n+static void i40e_reset_ch_rings(struct i40e_vsi *vsi, struct i40e_channel *ch)\n+{\n+\tstruct i40e_ring *tx_ring, *rx_ring;\n+\tu16 pf_q;\n+\tint i;\n+\n+\tfor (i = 0; i < ch->num_queue_pairs; i++) {\n+\t\tpf_q = ch->base_queue + i;\n+\t\ttx_ring = vsi->tx_rings[pf_q];\n+\t\ttx_ring->ch = NULL;\n+\t\trx_ring = vsi->rx_rings[pf_q];\n+\t\trx_ring->ch = NULL;\n+\t}\n+}\n+\n+/**\n+ * i40e_free_macvlan_channels\n+ * @vsi: the VSI we want to access\n+ *\n+ * This function frees the Qs of the channel VSI from\n+ * the stack and also deletes the channel VSIs which\n+ * serve as macvlans.\n+ */\n+static void i40e_free_macvlan_channels(struct i40e_vsi *vsi)\n+{\n+\tstruct i40e_channel *ch, *ch_tmp;\n+\tint ret;\n+\n+\tif (list_empty(&vsi->macvlan_list))\n+\t\treturn;\n+\n+\tlist_for_each_entry_safe(ch, ch_tmp, &vsi->macvlan_list, list) {\n+\t\tstruct i40e_vsi *parent_vsi;\n+\n+\t\tif (i40e_is_channel_macvlan(ch)) {\n+\t\t\ti40e_reset_ch_rings(vsi, ch);\n+\t\t\tclear_bit(ch->fwd->bit_no, vsi->fwd_bitmask);\n+\t\t\tnetdev_unbind_sb_channel(vsi->netdev, ch->fwd->netdev);\n+\t\t\tnetdev_set_sb_channel(ch->fwd->netdev, 0);\n+\t\t\tkfree(ch->fwd);\n+\t\t\tch->fwd = NULL;\n+\t\t}\n+\n+\t\tlist_del(&ch->list);\n+\t\tparent_vsi = ch->parent_vsi;\n+\t\tif (!parent_vsi || !ch->initialized) {\n+\t\t\tkfree(ch);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* remove the VSI */\n+\t\tret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,\n+\t\t\t\t\t NULL);\n+\t\tif (ret)\n+\t\t\tdev_err(&vsi->back->pdev->dev,\n+\t\t\t\t\"unable to remove channel (%d) for parent VSI(%d)\\n\",\n+\t\t\t\tch->seid, parent_vsi->seid);\n+\t\tkfree(ch);\n+\t}\n+\tvsi->macvlan_cnt = 0;\n+}\n+\n+/**\n+ * i40e_fwd_ring_up - bring the macvlan device up\n+ * @vsi: the VSI we want to access\n+ * @vdev: macvlan netdevice\n+ * @fwd: the private fwd structure\n+ */\n+static int i40e_fwd_ring_up(struct i40e_vsi *vsi, struct net_device *vdev,\n+\t\t\t struct i40e_fwd_adapter *fwd)\n+{\n+\tint ret = 0, num_tc = 1, i, aq_err;\n+\tstruct i40e_channel *ch, *ch_tmp;\n+\tstruct i40e_pf *pf = vsi->back;\n+\tstruct i40e_hw *hw = &pf->hw;\n+\n+\tif (list_empty(&vsi->macvlan_list))\n+\t\treturn -EINVAL;\n+\n+\t/* Go through the list and find an available channel */\n+\tlist_for_each_entry_safe(ch, ch_tmp, &vsi->macvlan_list, list) {\n+\t\tif (!i40e_is_channel_macvlan(ch)) {\n+\t\t\tch->fwd = fwd;\n+\t\t\t/* record configuration for macvlan interface in vdev */\n+\t\t\tfor (i = 0; i < num_tc; i++)\n+\t\t\t\tnetdev_bind_sb_channel_queue(vsi->netdev, vdev,\n+\t\t\t\t\t\t\t i,\n+\t\t\t\t\t\t\t ch->num_queue_pairs,\n+\t\t\t\t\t\t\t ch->base_queue);\n+\t\t\tfor (i = 0; i < ch->num_queue_pairs; i++) {\n+\t\t\t\tstruct i40e_ring *tx_ring, *rx_ring;\n+\t\t\t\tu16 pf_q;\n+\n+\t\t\t\tpf_q = ch->base_queue + i;\n+\n+\t\t\t\t/* Get to TX ring ptr */\n+\t\t\t\ttx_ring = vsi->tx_rings[pf_q];\n+\t\t\t\ttx_ring->ch = ch;\n+\n+\t\t\t\t/* Get the RX ring ptr */\n+\t\t\t\trx_ring = vsi->rx_rings[pf_q];\n+\t\t\t\trx_ring->ch = ch;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\t/* Guarantee all rings are updated before we update the\n+\t * MAC address filter.\n+\t */\n+\twmb();\n+\n+\t/* Add a mac filter */\n+\tret = i40e_add_macvlan_filter(hw, ch->seid, vdev->dev_addr, &aq_err);\n+\tif (ret) {\n+\t\t/* if we cannot add the MAC rule then disable the offload */\n+\t\tmacvlan_release_l2fw_offload(vdev);\n+\t\tfor (i = 0; i < ch->num_queue_pairs; i++) {\n+\t\t\tstruct i40e_ring *rx_ring;\n+\t\t\tu16 pf_q;\n+\n+\t\t\tpf_q = ch->base_queue + i;\n+\t\t\trx_ring = vsi->rx_rings[pf_q];\n+\t\t\trx_ring->netdev = NULL;\n+\t\t}\n+\t\tdev_info(&pf->pdev->dev,\n+\t\t\t \"Error adding mac filter on macvlan err %s, aq_err %s\\n\",\n+\t\t\t i40e_stat_str(hw, ret),\n+\t\t\t i40e_aq_str(hw, aq_err));\n+\t\tnetdev_err(vdev, \"L2fwd offload disabled to L2 filter error\\n\");\n+\t}\n+\treturn ret;\n+}\n+\n+/**\n+ * i40e_setup_macvlans - create the channels which will be macvlans\n+ * @vsi: the VSI we want to access\n+ * @macvlan_cnt: no. of macvlans to be setup\n+ * @qcnt: no. of Qs per macvlan\n+ * @vdev: macvlan netdevice\n+ */\n+static int i40e_setup_macvlans(struct i40e_vsi *vsi, u16 macvlan_cnt, u16 qcnt,\n+\t\t\t struct net_device *vdev)\n+{\n+\tstruct i40e_pf *pf = vsi->back;\n+\tstruct i40e_hw *hw = &pf->hw;\n+\tstruct i40e_vsi_context ctxt;\n+\tu16 sections, qmap, num_qps;\n+\tstruct i40e_channel *ch;\n+\tint i, pow, ret = 0;\n+\tu8 offset = 0;\n+\n+\tif (vsi->type != I40E_VSI_MAIN)\n+\t\treturn -EINVAL;\n+\tif (!macvlan_cnt)\n+\t\treturn -EINVAL;\n+\n+\tnum_qps = vsi->num_queue_pairs - (macvlan_cnt * qcnt);\n+\n+\t/* find the next higher power-of-2 of num queue pairs */\n+\tpow = fls(roundup_pow_of_two(num_qps) - 1);\n+\n+\tqmap = (offset << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |\n+\t\t(pow << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT);\n+\n+\t/* Setup context bits for the main VSI */\n+\tsections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;\n+\tsections |= I40E_AQ_VSI_PROP_SCHED_VALID;\n+\tmemset(&ctxt, 0, sizeof(ctxt));\n+\tctxt.seid = vsi->seid;\n+\tctxt.pf_num = vsi->back->hw.pf_id;\n+\tctxt.vf_num = 0;\n+\tctxt.uplink_seid = vsi->uplink_seid;\n+\tctxt.info = vsi->info;\n+\tctxt.info.tc_mapping[0] = cpu_to_le16(qmap);\n+\tctxt.info.mapping_flags |= cpu_to_le16(I40E_AQ_VSI_QUE_MAP_CONTIG);\n+\tctxt.info.queue_mapping[0] = cpu_to_le16(vsi->base_queue);\n+\tctxt.info.valid_sections |= cpu_to_le16(sections);\n+\n+\t/* Reconfigure RSS for main VSI with new max queue count */\n+\tvsi->rss_size = max_t(u16, num_qps, qcnt);\n+\tret = i40e_vsi_config_rss(vsi);\n+\tif (ret) {\n+\t\tdev_info(&pf->pdev->dev,\n+\t\t\t \"Failed to reconfig RSS for num_queues (%u)\\n\",\n+\t\t\t vsi->rss_size);\n+\t\treturn ret;\n+\t}\n+\tvsi->reconfig_rss = true;\n+\tdev_dbg(&vsi->back->pdev->dev,\n+\t\t\"Reconfigured RSS with num_queues (%u)\\n\", vsi->rss_size);\n+\tvsi->next_base_queue = num_qps;\n+\tvsi->cnt_q_avail = vsi->num_queue_pairs - num_qps;\n+\n+\t/* Update the VSI after updating the VSI queue-mapping\n+\t * information\n+\t */\n+\tret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);\n+\tif (ret) {\n+\t\tdev_info(&pf->pdev->dev,\n+\t\t\t \"Update vsi tc config failed, err %s aq_err %s\\n\",\n+\t\t\t i40e_stat_str(hw, ret),\n+\t\t\t i40e_aq_str(hw, hw->aq.asq_last_status));\n+\t\treturn ret;\n+\t}\n+\t/* update the local VSI info with updated queue map */\n+\ti40e_vsi_update_queue_map(vsi, &ctxt);\n+\tvsi->info.valid_sections = 0;\n+\n+\t/* Create channels for macvlans */\n+\tINIT_LIST_HEAD(&vsi->macvlan_list);\n+\tfor (i = 0; i < macvlan_cnt; i++) {\n+\t\tch = kzalloc(sizeof(*ch), GFP_KERNEL);\n+\t\tif (!ch) {\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto err_free;\n+\t\t}\n+\t\tINIT_LIST_HEAD(&ch->list);\n+\t\tch->num_queue_pairs = qcnt;\n+\t\tif (!i40e_setup_channel(pf, vsi, ch)) {\n+\t\t\tret = -EINVAL;\n+\t\t\tgoto err_free;\n+\t\t}\n+\t\tch->parent_vsi = vsi;\n+\t\tvsi->cnt_q_avail -= ch->num_queue_pairs;\n+\t\tvsi->macvlan_cnt++;\n+\t\tlist_add_tail(&ch->list, &vsi->macvlan_list);\n+\t}\n+\treturn ret;\n+\n+err_free:\n+\tdev_info(&pf->pdev->dev, \"Failed to setup macvlans\\n\");\n+\ti40e_free_macvlan_channels(vsi);\n+\treturn ret;\n+}\n+\n+/**\n+ * i40e_fwd_add - configure macvlans\n+ * @netdev: net device to configure\n+ * @vdev: macvlan netdevice\n+ **/\n+static void *i40e_fwd_add(struct net_device *netdev, struct net_device *vdev)\n+{\n+\tstruct i40e_netdev_priv *np = netdev_priv(netdev);\n+\tu16 q_per_macvlan = 0, macvlan_cnt = 0, vectors;\n+\tstruct i40e_vsi *vsi = np->vsi;\n+\tstruct i40e_pf *pf = vsi->back;\n+\tstruct i40e_fwd_adapter *fwd;\n+\tint avail_macvlan, ret;\n+\n+\tif ((pf->flags & I40E_FLAG_DCB_ENABLED)) {\n+\t\tnetdev_info(netdev, \"Macvlans are not supported when DCB is enabled\\n\");\n+\t\treturn ERR_PTR(-EINVAL);\n+\t}\n+\tif ((pf->flags & I40E_FLAG_TC_MQPRIO)) {\n+\t\tnetdev_info(netdev, \"Macvlans are not supported when HW TC offload is on\\n\");\n+\t\treturn ERR_PTR(-EINVAL);\n+\t}\n+\n+\t/* The macvlan device has to be a single Q device so that the\n+\t * tc_to_txq field can be reused to pick the tx queue.\n+\t */\n+\tif (netif_is_multiqueue(vdev))\n+\t\treturn ERR_PTR(-ERANGE);\n+\n+\tif (!vsi->macvlan_cnt) {\n+\t\t/* reserve bit 0 for the pf device */\n+\t\tset_bit(0, vsi->fwd_bitmask);\n+\n+\t\t/* Try to reserve as many queues for macvlans. First reserve\n+\t\t * 3/4th of max vectors, then half, then quarter and calculate\n+\t\t * Qs per macvlan as you go\n+\t\t */\n+\t\tvectors = pf->num_lan_msix;\n+\t\tif (vectors <= I40E_MAX_MACVLANS && vectors > 96) {\n+\t\t\t/* allocate 4 Qs per macvlan and 32 Qs to the PF*/\n+\t\t\tq_per_macvlan = 4;\n+\t\t\tmacvlan_cnt = (vectors - 32) / 4;\n+\t\t} else if (vectors <= 96 && vectors > 64) {\n+\t\t\t/* allocate 4 Qs per macvlan and 32 Qs to the PF*/\n+\t\t\tq_per_macvlan = 4;\n+\t\t\tmacvlan_cnt = (vectors - 32) / 4;\n+\t\t} else if (vectors <= 64 && vectors > 32) {\n+\t\t\t/* allocate 2 Qs per macvlan and 16 Qs to the PF*/\n+\t\t\tq_per_macvlan = 2;\n+\t\t\tmacvlan_cnt = (vectors - 16) / 2;\n+\t\t} else {\n+\t\t\t/* allocate 1 Q per macvlan 16 Qs to the PF*/\n+\t\t\tq_per_macvlan = 1;\n+\t\t\tmacvlan_cnt = (vectors - 16);\n+\t\t}\n+\t\tif (macvlan_cnt == 0)\n+\t\t\treturn ERR_PTR(-EBUSY);\n+\n+\t\t/* Quiesce VSI queues */\n+\t\ti40e_quiesce_vsi(vsi);\n+\n+\t\t/* sets up the macvlans but does not \"enable\" them */\n+\t\tret = i40e_setup_macvlans(vsi, macvlan_cnt, q_per_macvlan,\n+\t\t\t\t\t vdev);\n+\t\tif (ret)\n+\t\t\treturn ERR_PTR(ret);\n+\n+\t\t/* Unquiesce VSI */\n+\t\ti40e_unquiesce_vsi(vsi);\n+\t}\n+\tavail_macvlan = find_first_zero_bit(vsi->fwd_bitmask,\n+\t\t\t\t\t vsi->macvlan_cnt);\n+\tif (avail_macvlan >= I40E_MAX_MACVLANS)\n+\t\treturn ERR_PTR(-EBUSY);\n+\n+\t/* create the fwd struct */\n+\tfwd = kzalloc(sizeof(*fwd), GFP_KERNEL);\n+\tif (!fwd)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tset_bit(avail_macvlan, vsi->fwd_bitmask);\n+\tfwd->bit_no = avail_macvlan;\n+\tnetdev_set_sb_channel(vdev, avail_macvlan);\n+\tfwd->netdev = vdev;\n+\n+\tif (!netif_running(netdev))\n+\t\treturn fwd;\n+\n+\t/* Set fwd ring up */\n+\tret = i40e_fwd_ring_up(vsi, vdev, fwd);\n+\tif (ret) {\n+\t\t/* unbind the queues and drop the subordinate channel config */\n+\t\tnetdev_unbind_sb_channel(netdev, vdev);\n+\t\tnetdev_set_sb_channel(vdev, 0);\n+\n+\t\tkfree(fwd);\n+\t\treturn ERR_PTR(-EINVAL);\n+\t}\n+\treturn fwd;\n+}\n+\n+/**\n+ * i40e_del_all_macvlans - Delete all the mac filters on the channels\n+ * @vsi: the VSI we want to access\n+ */\n+static void i40e_del_all_macvlans(struct i40e_vsi *vsi)\n+{\n+\tstruct i40e_channel *ch, *ch_tmp;\n+\tstruct i40e_pf *pf = vsi->back;\n+\tstruct i40e_hw *hw = &pf->hw;\n+\tint aq_err, ret = 0;\n+\n+\tif (list_empty(&vsi->macvlan_list))\n+\t\treturn;\n+\n+\tlist_for_each_entry_safe(ch, ch_tmp, &vsi->macvlan_list, list) {\n+\t\tif (i40e_is_channel_macvlan(ch)) {\n+\t\t\tret = i40e_del_macvlan_filter(hw, ch->seid,\n+\t\t\t\t\t\t i40e_channel_mac(ch),\n+\t\t\t\t\t\t &aq_err);\n+\t\t\tif (!ret) {\n+\t\t\t\t/* Reset queue contexts */\n+\t\t\t\ti40e_reset_ch_rings(vsi, ch);\n+\t\t\t\tclear_bit(ch->fwd->bit_no, vsi->fwd_bitmask);\n+\t\t\t\tnetdev_unbind_sb_channel(vsi->netdev,\n+\t\t\t\t\t\t\t ch->fwd->netdev);\n+\t\t\t\tnetdev_set_sb_channel(ch->fwd->netdev, 0);\n+\t\t\t\tkfree(ch->fwd);\n+\t\t\t\tch->fwd = NULL;\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n+/**\n+ * i40e_fwd_del - delete macvlan interfaces\n+ * @netdev: net device to configure\n+ * @vdev: macvlan netdevice\n+ */\n+static void i40e_fwd_del(struct net_device *netdev, void *vdev)\n+{\n+\tstruct i40e_netdev_priv *np = netdev_priv(netdev);\n+\tstruct i40e_fwd_adapter *fwd = vdev;\n+\tstruct i40e_channel *ch, *ch_tmp;\n+\tstruct i40e_vsi *vsi = np->vsi;\n+\tstruct i40e_pf *pf = vsi->back;\n+\tstruct i40e_hw *hw = &pf->hw;\n+\tint aq_err, ret = 0;\n+\n+\t/* Find the channel associated with the macvlan and del mac filter */\n+\tlist_for_each_entry_safe(ch, ch_tmp, &vsi->macvlan_list, list) {\n+\t\tif (i40e_is_channel_macvlan(ch) &&\n+\t\t ether_addr_equal(i40e_channel_mac(ch),\n+\t\t\t\t fwd->netdev->dev_addr)) {\n+\t\t\tret = i40e_del_macvlan_filter(hw, ch->seid,\n+\t\t\t\t\t\t i40e_channel_mac(ch),\n+\t\t\t\t\t\t &aq_err);\n+\t\t\tif (!ret) {\n+\t\t\t\t/* Reset queue contexts */\n+\t\t\t\ti40e_reset_ch_rings(vsi, ch);\n+\t\t\t\tclear_bit(ch->fwd->bit_no, vsi->fwd_bitmask);\n+\t\t\t\tnetdev_unbind_sb_channel(netdev, fwd->netdev);\n+\t\t\t\tnetdev_set_sb_channel(fwd->netdev, 0);\n+\t\t\t\tkfree(ch->fwd);\n+\t\t\t\tch->fwd = NULL;\n+\t\t\t} else {\n+\t\t\t\tdev_info(&pf->pdev->dev,\n+\t\t\t\t\t \"Error deleting mac filter on macvlan err %s, aq_err %s\\n\",\n+\t\t\t\t\t i40e_stat_str(hw, ret),\n+\t\t\t\t\t i40e_aq_str(hw, aq_err));\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+}\n+\n /**\n * i40e_setup_tc - configure multiple traffic classes\n * @netdev: net device to configure\n@@ -11493,6 +11965,9 @@ static int i40e_set_features(struct net_device *netdev,\n \t\treturn -EINVAL;\n \t}\n \n+\tif (!(features & NETIF_F_HW_L2FW_DOFFLOAD) && vsi->macvlan_cnt)\n+\t\ti40e_del_all_macvlans(vsi);\n+\n \tneed_reset = i40e_set_ntuple(pf, features);\n \n \tif (need_reset)\n@@ -12237,6 +12712,8 @@ static const struct net_device_ops i40e_netdev_ops = {\n \t.ndo_bpf\t\t= i40e_xdp,\n \t.ndo_xdp_xmit\t\t= i40e_xdp_xmit,\n \t.ndo_xsk_async_xmit\t= i40e_xsk_async_xmit,\n+\t.ndo_dfwd_add_station\t= i40e_fwd_add,\n+\t.ndo_dfwd_del_station\t= i40e_fwd_del,\n };\n \n /**\n@@ -12296,6 +12773,9 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)\n \t/* record features VLANs can make use of */\n \tnetdev->vlan_features |= hw_enc_features | NETIF_F_TSO_MANGLEID;\n \n+\t/* enable macvlan offloads */\n+\tnetdev->hw_features |= NETIF_F_HW_L2FW_DOFFLOAD;\n+\n \thw_features = hw_enc_features\t\t|\n \t\t NETIF_F_HW_VLAN_CTAG_TX\t|\n \t\t NETIF_F_HW_VLAN_CTAG_RX;\n", "prefixes": [ "v4" ] }