Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/860166/?format=api
{ "id": 860166, "url": "http://patchwork.ozlabs.org/api/patches/860166/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20180112193251.11739-4-jeffrey.t.kirsher@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": "<20180112193251.11739-4-jeffrey.t.kirsher@intel.com>", "list_archive_url": null, "date": "2018-01-12T19:32:43", "name": "[04/12] i40e: Enable ADq and create queue channel/s on VF", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "fa627e2bc9df825b60606031556a1600e94dd0a1", "submitter": { "id": 473, "url": "http://patchwork.ozlabs.org/api/people/473/?format=api", "name": "Kirsher, Jeffrey T", "email": "jeffrey.t.kirsher@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/20180112193251.11739-4-jeffrey.t.kirsher@intel.com/mbox/", "series": [ { "id": 23043, "url": "http://patchwork.ozlabs.org/api/series/23043/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=23043", "date": "2018-01-12T19:32:45", "name": "[01/12] i40evf: Fix link up issue when queues are disabled", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/23043/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/860166/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/860166/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.133; helo=hemlock.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)", "Received": [ "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3zJCZj53l9z9s7c\n\tfor <incoming@patchwork.ozlabs.org>;\n\tSat, 13 Jan 2018 06:33:01 +1100 (AEDT)", "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 0E79C89EF7;\n\tFri, 12 Jan 2018 19:33:00 +0000 (UTC)", "from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id 2tcA+hG5AZJD; Fri, 12 Jan 2018 19:32:55 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 02E4289F29;\n\tFri, 12 Jan 2018 19:32:54 +0000 (UTC)", "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\tby ash.osuosl.org (Postfix) with ESMTP id 33B861C002D\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tFri, 12 Jan 2018 19:32:52 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 2F4CF89E92\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tFri, 12 Jan 2018 19:32:52 +0000 (UTC)", "from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id r9kDmFKieewQ for <intel-wired-lan@lists.osuosl.org>;\n\tFri, 12 Jan 2018 19:32:48 +0000 (UTC)", "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby hemlock.osuosl.org (Postfix) with ESMTPS id 5228989EDF\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tFri, 12 Jan 2018 19:32:48 +0000 (UTC)", "from orsmga003.jf.intel.com ([10.7.209.27])\n\tby orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t12 Jan 2018 11:32:47 -0800", "from jtkirshe-nuc.jf.intel.com ([134.134.177.151])\n\tby orsmga003.jf.intel.com with ESMTP; 12 Jan 2018 11:32:47 -0800" ], "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.46,350,1511856000\"; d=\"scan'208\";a=\"19654870\"", "From": "Jeff Kirsher <jeffrey.t.kirsher@intel.com>", "To": "intel-wired-lan@lists.osuosl.org", "Date": "Fri, 12 Jan 2018 11:32:43 -0800", "Message-Id": "<20180112193251.11739-4-jeffrey.t.kirsher@intel.com>", "X-Mailer": "git-send-email 2.14.3", "In-Reply-To": "<20180112193251.11739-1-jeffrey.t.kirsher@intel.com>", "References": "<20180112193251.11739-1-jeffrey.t.kirsher@intel.com>", "Subject": "[Intel-wired-lan] [PATCH 04/12] i40e: Enable ADq and create queue\n\tchannel/s on VF", "X-BeenThere": "intel-wired-lan@osuosl.org", "X-Mailman-Version": "2.1.24", "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": "From: Avinash Dayanand <avinash.dayanand@intel.com>\n\nThis patch enables ADq and creates queue channels on a VF. An ADq\nenabled VF can have upto 4 VSIs and each one of them represents\na traffic class and this is termed as a queue channel. Each of these\nVSIs can have up to 4 queues. This patch services the request for\nenabling ADq and adds queue channel based on the TC mqprio info\nprovided by the user in the VF.\n\nInitially a check is made to see if spoof check is OFF, if not ADq\nwill not be enabled. PF notifies VF for a reset in order to complete\nthe creation of ADq resources i.e. creation of additional VSIs and\nallocation of queues as per TC information, all in the reset path.\n\nSteps:", "diff": "======\n1. Turn off the spoof check\n2. Enable ADq using tc mqprio command with or without rate limit.\n3. Pass traffic.\n\nExample:\n========\n% ip link set dev eth0 vf 0 spoofchk off\n% tc qdisc add dev $iface root mqprio num_tc 4 map\\\n\t0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 queues\\\n\t4@0 4@4 4@8 4@8 hw 1 mode channel\n\nExpected results:\n=================\n1. Total number of queues for the VF should be sum of queues of all TCs.\n2. Traffic flow should be normal without errors.\n\nSigned-off-by: Avinash Dayanand <avinash.dayanand@intel.com>\n---\n drivers/net/ethernet/intel/i40e/i40e_type.h | 2 +-\n drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 429 +++++++++++++++++----\n drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 17 +\n 3 files changed, 379 insertions(+), 69 deletions(-)\n\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h\nindex cd294e6a8587..b0eed8c0b2f2 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_type.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h\n@@ -39,7 +39,7 @@\n #define I40E_MASK(mask, shift) ((u32)(mask) << (shift))\n \n #define I40E_MAX_VSI_QP\t\t\t16\n-#define I40E_MAX_VF_VSI\t\t\t3\n+#define I40E_MAX_VF_VSI\t\t\t4\n #define I40E_MAX_CHAINED_RX_BUFFERS\t5\n #define I40E_MAX_PF_UDP_OFFLOAD_PORTS\t16\n \ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c\nindex e9309fb9084b..7d939a5dc6a9 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c\n@@ -257,6 +257,38 @@ static u16 i40e_vc_get_pf_queue_id(struct i40e_vf *vf, u16 vsi_id,\n \treturn pf_queue_id;\n }\n \n+/**\n+ * i40e_get_real_pf_qid\n+ * @vf: pointer to the VF info\n+ * @vsi_id: vsi id\n+ * @queue_id: queue number\n+ *\n+ * wrapper function to get pf_queue_id handling ADq code as well\n+ **/\n+static u16 i40e_get_real_pf_qid(struct i40e_vf *vf, u16 vsi_id, u16 queue_id)\n+{\n+\tint i;\n+\n+\tif (vf->adq_enabled) {\n+\t\t/* Although VF considers all the queues(can be 1 to 16) as its\n+\t\t * own but they may actually belong to different VSIs(upto 4).\n+\t\t * We need to find which queues belongs to which VSI.\n+\t\t */\n+\t\tfor (i = 0; i < vf->num_tc; i++) {\n+\t\t\tif (queue_id < vf->ch[i].num_qps) {\n+\t\t\t\tvsi_id = vf->ch[i].vsi_id;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\t/* find right queue id which is relative to a\n+\t\t\t * given VSI.\n+\t\t\t */\n+\t\t\tqueue_id -= vf->ch[i].num_qps;\n+\t\t\t}\n+\t\t}\n+\n+\treturn i40e_vc_get_pf_queue_id(vf, vsi_id, queue_id);\n+}\n+\n /**\n * i40e_config_irq_link_list\n * @vf: pointer to the VF info\n@@ -310,7 +342,7 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id,\n \n \tvsi_queue_id = next_q / I40E_VIRTCHNL_SUPPORTED_QTYPES;\n \tqtype = next_q % I40E_VIRTCHNL_SUPPORTED_QTYPES;\n-\tpf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id, vsi_queue_id);\n+\tpf_queue_id = i40e_get_real_pf_qid(vf, vsi_id, vsi_queue_id);\n \treg = ((qtype << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) | pf_queue_id);\n \n \twr32(hw, reg_idx, reg);\n@@ -333,8 +365,9 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id,\n \t\tif (next_q < size) {\n \t\t\tvsi_queue_id = next_q / I40E_VIRTCHNL_SUPPORTED_QTYPES;\n \t\t\tqtype = next_q % I40E_VIRTCHNL_SUPPORTED_QTYPES;\n-\t\t\tpf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id,\n-\t\t\t\t\t\t\t vsi_queue_id);\n+\t\t\tpf_queue_id = i40e_get_real_pf_qid(vf,\n+\t\t\t\t\t\t\t vsi_id,\n+\t\t\t\t\t\t\t vsi_queue_id);\n \t\t} else {\n \t\t\tpf_queue_id = I40E_QUEUE_END_OF_LIST;\n \t\t\tqtype = 0;\n@@ -669,18 +702,19 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id,\n /**\n * i40e_alloc_vsi_res\n * @vf: pointer to the VF info\n- * @type: type of VSI to allocate\n+ * @idx: VSI index, applies only for ADq mode, zero otherwise\n *\n * alloc VF vsi context & resources\n **/\n-static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)\n+static int i40e_alloc_vsi_res(struct i40e_vf *vf, u8 idx)\n {\n \tstruct i40e_mac_filter *f = NULL;\n \tstruct i40e_pf *pf = vf->pf;\n \tstruct i40e_vsi *vsi;\n \tint ret = 0;\n \n-\tvsi = i40e_vsi_setup(pf, type, pf->vsi[pf->lan_vsi]->seid, vf->vf_id);\n+\tvsi = i40e_vsi_setup(pf, I40E_VSI_SRIOV, pf->vsi[pf->lan_vsi]->seid,\n+\t\t\t vf->vf_id);\n \n \tif (!vsi) {\n \t\tdev_err(&pf->pdev->dev,\n@@ -689,7 +723,8 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)\n \t\tret = -ENOENT;\n \t\tgoto error_alloc_vsi_res;\n \t}\n-\tif (type == I40E_VSI_SRIOV) {\n+\n+\tif (!idx) {\n \t\tu64 hena = i40e_pf_get_default_rss_hena(pf);\n \t\tu8 broadcast[ETH_ALEN];\n \n@@ -721,12 +756,17 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)\n \t\tspin_unlock_bh(&vsi->mac_filter_hash_lock);\n \t\twr32(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id), (u32)hena);\n \t\twr32(&pf->hw, I40E_VFQF_HENA1(1, vf->vf_id), (u32)(hena >> 32));\n+\t\t/* program mac filter only for VF VSI */\n+\t\tret = i40e_sync_vsi_filters(vsi);\n+\t\tif (ret)\n+\t\t\tdev_err(&pf->pdev->dev, \"Unable to program ucast filters\\n\");\n \t}\n \n-\t/* program mac filter */\n-\tret = i40e_sync_vsi_filters(vsi);\n-\tif (ret)\n-\t\tdev_err(&pf->pdev->dev, \"Unable to program ucast filters\\n\");\n+\t/* storing vsi index and id for ADq and don't apply the mac filter */\n+\tif (vf->adq_enabled) {\n+\t\tvf->ch[idx].vsi_idx = vsi->idx;\n+\t\tvf->ch[idx].vsi_id = vsi->id;\n+\t}\n \n \t/* Set VF bandwidth if specified */\n \tif (vf->tx_rate) {\n@@ -741,6 +781,92 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)\n \treturn ret;\n }\n \n+/**\n+ * i40e_map_pf_queues_to_vsi\n+ * @vf: pointer to the VF info\n+ *\n+ * PF maps LQPs to a VF by programming VSILAN_QTABLE & VPLAN_QTABLE. This\n+ * function takes care of first part VSILAN_QTABLE, mapping pf queues to VSI.\n+ **/\n+static void i40e_map_pf_queues_to_vsi(struct i40e_vf *vf)\n+{\n+\tstruct i40e_pf *pf = vf->pf;\n+\tstruct i40e_hw *hw = &pf->hw;\n+\tu32 reg, num_tc = 1; /* VF has at least one traffic class */\n+\tu16 vsi_id, qps;\n+\tint i, j;\n+\n+\tif (vf->adq_enabled)\n+\t\tnum_tc = vf->num_tc;\n+\n+\tfor (i = 0; i < num_tc; i++) {\n+\t\tif (vf->adq_enabled) {\n+\t\t\tqps = vf->ch[i].num_qps;\n+\t\t\tvsi_id = vf->ch[i].vsi_id;\n+\t\t} else {\n+\t\t\tqps = pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs;\n+\t\t\tvsi_id = vf->lan_vsi_id;\n+\t\t}\n+\n+\t\tfor (j = 0; j < 7; j++) {\n+\t\t\tif (j * 2 >= qps) {\n+\t\t\t\t/* end of list */\n+\t\t\t\treg = 0x07FF07FF;\n+\t\t\t} else {\n+\t\t\t\tu16 qid = i40e_vc_get_pf_queue_id(vf,\n+\t\t\t\t\t\t\t\t vsi_id,\n+\t\t\t\t\t\t\t\t j * 2);\n+\t\t\t\treg = qid;\n+\t\t\t\tqid = i40e_vc_get_pf_queue_id(vf, vsi_id,\n+\t\t\t\t\t\t\t (j * 2) + 1);\n+\t\t\t\treg |= qid << 16;\n+\t\t\t}\n+\t\t\ti40e_write_rx_ctl(hw,\n+\t\t\t\t\t I40E_VSILAN_QTABLE(j, vsi_id),\n+\t\t\t\t\t reg);\n+\t\t}\n+\t}\n+}\n+\n+/**\n+ * i40e_map_pf_to_vf_queues\n+ * @vf: pointer to the VF info\n+ *\n+ * PF maps LQPs to a VF by programming VSILAN_QTABLE & VPLAN_QTABLE. This\n+ * function takes care of the second part VPLAN_QTABLE & completes vf mappings.\n+ **/\n+static void i40e_map_pf_to_vf_queues(struct i40e_vf *vf)\n+{\n+\tstruct i40e_pf *pf = vf->pf;\n+\tstruct i40e_hw *hw = &pf->hw;\n+\tu32 reg, total_qps = 0;\n+\tu32 qps, num_tc = 1; /* VF has at least one traffic class */\n+\tu16 vsi_id, qid;\n+\tint i, j;\n+\n+\tif (vf->adq_enabled)\n+\t\tnum_tc = vf->num_tc;\n+\n+\tfor (i = 0; i < num_tc; i++) {\n+\t\tif (vf->adq_enabled) {\n+\t\t\tqps = vf->ch[i].num_qps;\n+\t\t\tvsi_id = vf->ch[i].vsi_id;\n+\t\t} else {\n+\t\t\tqps = pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs;\n+\t\t\tvsi_id = vf->lan_vsi_id;\n+\t\t}\n+\n+\t\tfor (j = 0; j < qps; j++) {\n+\t\t\tqid = i40e_vc_get_pf_queue_id(vf, vsi_id, j);\n+\n+\t\t\treg = (qid & I40E_VPLAN_QTABLE_QINDEX_MASK);\n+\t\t\twr32(hw, I40E_VPLAN_QTABLE(total_qps, vf->vf_id),\n+\t\t\t reg);\n+\t\t\ttotal_qps++;\n+\t\t}\n+\t}\n+}\n+\n /**\n * i40e_enable_vf_mappings\n * @vf: pointer to the VF info\n@@ -751,8 +877,7 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf)\n {\n \tstruct i40e_pf *pf = vf->pf;\n \tstruct i40e_hw *hw = &pf->hw;\n-\tu32 reg, total_queue_pairs = 0;\n-\tint j;\n+\tu32 reg;\n \n \t/* Tell the hardware we're using noncontiguous mapping. HW requires\n \t * that VF queues be mapped using this method, even when they are\n@@ -765,30 +890,8 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf)\n \treg = I40E_VPLAN_MAPENA_TXRX_ENA_MASK;\n \twr32(hw, I40E_VPLAN_MAPENA(vf->vf_id), reg);\n \n-\t/* map PF queues to VF queues */\n-\tfor (j = 0; j < pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs; j++) {\n-\t\tu16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id, j);\n-\n-\t\treg = (qid & I40E_VPLAN_QTABLE_QINDEX_MASK);\n-\t\twr32(hw, I40E_VPLAN_QTABLE(total_queue_pairs, vf->vf_id), reg);\n-\t\ttotal_queue_pairs++;\n-\t}\n-\n-\t/* map PF queues to VSI */\n-\tfor (j = 0; j < 7; j++) {\n-\t\tif (j * 2 >= pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs) {\n-\t\t\treg = 0x07FF07FF;\t/* unused */\n-\t\t} else {\n-\t\t\tu16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id,\n-\t\t\t\t\t\t\t j * 2);\n-\t\t\treg = qid;\n-\t\t\tqid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id,\n-\t\t\t\t\t\t (j * 2) + 1);\n-\t\t\treg |= qid << 16;\n-\t\t}\n-\t\ti40e_write_rx_ctl(hw, I40E_VSILAN_QTABLE(j, vf->lan_vsi_id),\n-\t\t\t\t reg);\n-\t}\n+\ti40e_map_pf_to_vf_queues(vf);\n+\ti40e_map_pf_queues_to_vsi(vf);\n \n \ti40e_flush(hw);\n }\n@@ -824,7 +927,7 @@ static void i40e_free_vf_res(struct i40e_vf *vf)\n \tstruct i40e_pf *pf = vf->pf;\n \tstruct i40e_hw *hw = &pf->hw;\n \tu32 reg_idx, reg;\n-\tint i, msix_vf;\n+\tint i, j, msix_vf;\n \n \t/* Start by disabling VF's configuration API to prevent the OS from\n \t * accessing the VF's VSI after it's freed / invalidated.\n@@ -846,6 +949,20 @@ static void i40e_free_vf_res(struct i40e_vf *vf)\n \t\tvf->lan_vsi_id = 0;\n \t\tvf->num_mac = 0;\n \t}\n+\n+\t/* do the accounting and remove additional ADq VSI's */\n+\tif (vf->adq_enabled && vf->ch[0].vsi_idx) {\n+\t\tfor (j = 0; j < vf->num_tc; j++) {\n+\t\t\t/* At this point VSI0 is already released so don't\n+\t\t\t * release it again and only clear their values in\n+\t\t\t * structure variables\n+\t\t\t */\n+\t\t\tif (j)\n+\t\t\t\ti40e_vsi_release(pf->vsi[vf->ch[j].vsi_idx]);\n+\t\t\tvf->ch[j].vsi_idx = 0;\n+\t\t\tvf->ch[j].vsi_id = 0;\n+\t\t}\n+\t}\n \tmsix_vf = pf->hw.func_caps.num_msix_vectors_vf;\n \n \t/* disable interrupts so the VF starts in a known state */\n@@ -891,7 +1008,7 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf)\n {\n \tstruct i40e_pf *pf = vf->pf;\n \tint total_queue_pairs = 0;\n-\tint ret;\n+\tint ret, idx;\n \n \tif (vf->num_req_queues &&\n \t vf->num_req_queues <= pf->queues_left + I40E_DEFAULT_QUEUES_PER_VF)\n@@ -900,11 +1017,30 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf)\n \t\tpf->num_vf_qps = I40E_DEFAULT_QUEUES_PER_VF;\n \n \t/* allocate hw vsi context & associated resources */\n-\tret = i40e_alloc_vsi_res(vf, I40E_VSI_SRIOV);\n+\tret = i40e_alloc_vsi_res(vf, 0);\n \tif (ret)\n \t\tgoto error_alloc;\n \ttotal_queue_pairs += pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs;\n \n+\t/* allocate additional vsis based on tc information for ADq */\n+\tif (vf->adq_enabled) {\n+\t\tif (pf->queues_left >=\n+\t\t (I40E_MAX_VF_QUEUES - I40E_DEFAULT_QUEUES_PER_VF)) {\n+\t\t\t/* TC 0 always belongs to VF VSI */\n+\t\t\tfor (idx = 1; idx < vf->num_tc; idx++) {\n+\t\t\t\tret = i40e_alloc_vsi_res(vf, idx);\n+\t\t\t\tif (ret)\n+\t\t\t\t\tgoto error_alloc;\n+\t\t\t}\n+\t\t\t/* send correct number of queues */\n+\t\t\ttotal_queue_pairs = I40E_MAX_VF_QUEUES;\n+\t\t} else {\n+\t\t\tdev_info(&pf->pdev->dev, \"VF %d: Not enough queues to allocate, disabling ADq\\n\",\n+\t\t\t\t vf->vf_id);\n+\t\t\tvf->adq_enabled = false;\n+\t\t}\n+\t}\n+\n \t/* We account for each VF to get a default number of queue pairs. If\n \t * the VF has now requested more, we need to account for that to make\n \t * certain we never request more queues than we actually have left in\n@@ -1631,6 +1767,9 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)\n \tif (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_REQ_QUEUES)\n \t\tvfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_REQ_QUEUES;\n \n+\tif (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ADQ)\n+\t\tvfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ADQ;\n+\n \tvfres->num_vsis = num_vsis;\n \tvfres->num_queue_pairs = vf->num_queue_pairs;\n \tvfres->max_vectors = pf->hw.func_caps.num_msix_vectors_vf;\n@@ -1855,27 +1994,37 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)\n \t (struct virtchnl_vsi_queue_config_info *)msg;\n \tstruct virtchnl_queue_pair_info *qpi;\n \tstruct i40e_pf *pf = vf->pf;\n-\tu16 vsi_id, vsi_queue_id;\n+\tu16 vsi_id, vsi_queue_id = 0;\n \ti40e_status aq_ret = 0;\n-\tint i;\n+\tint i, j = 0, idx = 0;\n+\n+\tvsi_id = qci->vsi_id;\n \n \tif (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {\n \t\taq_ret = I40E_ERR_PARAM;\n \t\tgoto error_param;\n \t}\n \n-\tvsi_id = qci->vsi_id;\n \tif (!i40e_vc_isvalid_vsi_id(vf, vsi_id)) {\n \t\taq_ret = I40E_ERR_PARAM;\n \t\tgoto error_param;\n \t}\n+\n \tfor (i = 0; i < qci->num_queue_pairs; i++) {\n \t\tqpi = &qci->qpair[i];\n-\t\tvsi_queue_id = qpi->txq.queue_id;\n-\t\tif ((qpi->txq.vsi_id != vsi_id) ||\n-\t\t (qpi->rxq.vsi_id != vsi_id) ||\n-\t\t (qpi->rxq.queue_id != vsi_queue_id) ||\n-\t\t !i40e_vc_isvalid_queue_id(vf, vsi_id, vsi_queue_id)) {\n+\n+\t\tif (!vf->adq_enabled) {\n+\t\t\tvsi_queue_id = qpi->txq.queue_id;\n+\n+\t\t\tif (qpi->txq.vsi_id != qci->vsi_id ||\n+\t\t\t qpi->rxq.vsi_id != qci->vsi_id ||\n+\t\t\t qpi->rxq.queue_id != vsi_queue_id) {\n+\t\t\t\taq_ret = I40E_ERR_PARAM;\n+\t\t\t\tgoto error_param;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (!i40e_vc_isvalid_queue_id(vf, vsi_id, vsi_queue_id)) {\n \t\t\taq_ret = I40E_ERR_PARAM;\n \t\t\tgoto error_param;\n \t\t}\n@@ -1887,9 +2036,33 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)\n \t\t\taq_ret = I40E_ERR_PARAM;\n \t\t\tgoto error_param;\n \t\t}\n+\n+\t\t/* For ADq there can be upto 4 VSIs with max 4 queues each.\n+\t\t * VF does not know about these additional VSIs and all\n+\t\t * it cares is about its own queues. PF configures these queues\n+\t\t * to its appropriate VSIs based on TC mapping\n+\t\t **/\n+\t\tif (vf->adq_enabled) {\n+\t\t\tif (j == (vf->ch[idx].num_qps - 1)) {\n+\t\t\t\tidx++;\n+\t\t\t\tj = 0; /* resetting the queue count */\n+\t\t\t\tvsi_queue_id = 0;\n+\t\t\t} else {\n+\t\t\t\tj++;\n+\t\t\t\tvsi_queue_id++;\n+\t\t\t}\n+\t\t\tvsi_id = vf->ch[idx].vsi_id;\n+\t\t}\n \t}\n \t/* set vsi num_queue_pairs in use to num configured by VF */\n-\tpf->vsi[vf->lan_vsi_idx]->num_queue_pairs = qci->num_queue_pairs;\n+\tif (!vf->adq_enabled) {\n+\t\tpf->vsi[vf->lan_vsi_idx]->num_queue_pairs =\n+\t\t\tqci->num_queue_pairs;\n+\t} else {\n+\t\tfor (i = 0; i < vf->num_tc; i++)\n+\t\t\tpf->vsi[vf->ch[i].vsi_idx]->num_queue_pairs =\n+\t\t\t vf->ch[i].num_qps;\n+\t}\n \n error_param:\n \t/* send the response to the VF */\n@@ -1897,6 +2070,33 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)\n \t\t\t\t aq_ret);\n }\n \n+/**\n+ * i40e_validate_queue_map\n+ * @vsi_id: vsi id\n+ * @queuemap: tx or rx queue map\n+ *\n+ * check if tx or rx queue map is valid\n+ **/\n+static int i40e_validate_queue_map(struct i40e_vf *vf, u16 vsi_id,\n+\t\t\t\t unsigned long queuemap)\n+{\n+\tu16 vsi_queue_id, queue_id;\n+\n+\tfor_each_set_bit(vsi_queue_id, &queuemap, I40E_MAX_VSI_QP) {\n+\t\tif (vf->adq_enabled) {\n+\t\t\tvsi_id = vf->ch[vsi_queue_id / I40E_MAX_VF_VSI].vsi_id;\n+\t\t\tqueue_id = (vsi_queue_id % I40E_DEFAULT_QUEUES_PER_VF);\n+\t\t} else {\n+\t\t\tqueue_id = vsi_queue_id;\n+\t\t}\n+\n+\t\tif (!i40e_vc_isvalid_queue_id(vf, vsi_id, queue_id))\n+\t\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n /**\n * i40e_vc_config_irq_map_msg\n * @vf: pointer to the VF info\n@@ -1911,9 +2111,8 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)\n \tstruct virtchnl_irq_map_info *irqmap_info =\n \t (struct virtchnl_irq_map_info *)msg;\n \tstruct virtchnl_vector_map *map;\n-\tu16 vsi_id, vsi_queue_id, vector_id;\n+\tu16 vsi_id, vector_id;\n \ti40e_status aq_ret = 0;\n-\tunsigned long tempmap;\n \tint i;\n \n \tif (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {\n@@ -1923,7 +2122,6 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)\n \n \tfor (i = 0; i < irqmap_info->num_vectors; i++) {\n \t\tmap = &irqmap_info->vecmap[i];\n-\n \t\tvector_id = map->vector_id;\n \t\tvsi_id = map->vsi_id;\n \t\t/* validate msg params */\n@@ -1933,23 +2131,14 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)\n \t\t\tgoto error_param;\n \t\t}\n \n-\t\t/* lookout for the invalid queue index */\n-\t\ttempmap = map->rxq_map;\n-\t\tfor_each_set_bit(vsi_queue_id, &tempmap, I40E_MAX_VSI_QP) {\n-\t\t\tif (!i40e_vc_isvalid_queue_id(vf, vsi_id,\n-\t\t\t\t\t\t vsi_queue_id)) {\n-\t\t\t\taq_ret = I40E_ERR_PARAM;\n-\t\t\t\tgoto error_param;\n-\t\t\t}\n+\t\tif (i40e_validate_queue_map(vf, vsi_id, map->rxq_map)) {\n+\t\t\taq_ret = I40E_ERR_PARAM;\n+\t\t\tgoto error_param;\n \t\t}\n \n-\t\ttempmap = map->txq_map;\n-\t\tfor_each_set_bit(vsi_queue_id, &tempmap, I40E_MAX_VSI_QP) {\n-\t\t\tif (!i40e_vc_isvalid_queue_id(vf, vsi_id,\n-\t\t\t\t\t\t vsi_queue_id)) {\n-\t\t\t\taq_ret = I40E_ERR_PARAM;\n-\t\t\t\tgoto error_param;\n-\t\t\t}\n+\t\tif (i40e_validate_queue_map(vf, vsi_id, map->txq_map)) {\n+\t\t\taq_ret = I40E_ERR_PARAM;\n+\t\t\tgoto error_param;\n \t\t}\n \n \t\ti40e_config_irq_link_list(vf, vsi_id, map);\n@@ -1975,6 +2164,7 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)\n \tstruct i40e_pf *pf = vf->pf;\n \tu16 vsi_id = vqs->vsi_id;\n \ti40e_status aq_ret = 0;\n+\tint i;\n \n \tif (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {\n \t\taq_ret = I40E_ERR_PARAM;\n@@ -1993,6 +2183,16 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)\n \n \tif (i40e_vsi_start_rings(pf->vsi[vf->lan_vsi_idx]))\n \t\taq_ret = I40E_ERR_TIMEOUT;\n+\n+\t/* need to start the rings for additional ADq VSI's as well */\n+\tif (vf->adq_enabled) {\n+\t\t/* zero belongs to LAN VSI */\n+\t\tfor (i = 1; i < vf->num_tc; i++) {\n+\t\t\tif (i40e_vsi_start_rings(pf->vsi[vf->ch[i].vsi_idx]))\n+\t\t\t\taq_ret = I40E_ERR_TIMEOUT;\n+\t\t}\n+\t}\n+\n error_param:\n \t/* send the response to the VF */\n \treturn i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES,\n@@ -2687,6 +2887,97 @@ static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg,\n \t\t\t\t aq_ret);\n }\n \n+/**\n+ * i40e_vc_add_qch_msg: Add queue channel and enable ADq\n+ * @vf: pointer to the VF info\n+ * @msg: pointer to the msg buffer\n+ **/\n+static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)\n+{\n+\tstruct virtchnl_tc_info *tci =\n+\t\t(struct virtchnl_tc_info *)msg;\n+\tstruct i40e_pf *pf = vf->pf;\n+\tint i, adq_request_qps = 0;\n+\ti40e_status aq_ret = 0;\n+\n+\tif (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {\n+\t\taq_ret = I40E_ERR_PARAM;\n+\t\tgoto err;\n+\t}\n+\n+\t/* ADq cannot be applied if spoof check is ON */\n+\tif (vf->spoofchk) {\n+\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\"Spoof check is ON, turn it OFF to enable ADq\\n\");\n+\t\taq_ret = I40E_ERR_PARAM;\n+\t\tgoto err;\n+\t}\n+\n+\tif (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ADQ)) {\n+\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\"VF %d attempting to enable ADq, but hasn't properly negotiated that capability\\n\",\n+\t\t\tvf->vf_id);\n+\t\taq_ret = I40E_ERR_PARAM;\n+\t\tgoto err;\n+\t}\n+\n+\t/* max number of traffic classes for VF currently capped at 4 */\n+\tif (!tci->num_tc || tci->num_tc > I40E_MAX_VF_VSI) {\n+\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\"VF %d trying to set %u TCs, valid range 1-4 TCs per VF\\n\",\n+\t\t\tvf->vf_id, tci->num_tc);\n+\t\taq_ret = I40E_ERR_PARAM;\n+\t\tgoto err;\n+\t}\n+\n+\t/* validate queues for each TC */\n+\tfor (i = 0; i < tci->num_tc; i++)\n+\t\tif (!tci->list[i].count ||\n+\t\t tci->list[i].count > I40E_DEFAULT_QUEUES_PER_VF) {\n+\t\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\t\"VF %d: TC %d trying to set %u queues, valid range 1-4 queues per TC\\n\",\n+\t\t\t\tvf->vf_id, i, tci->list[i].count);\n+\t\t\taq_ret = I40E_ERR_PARAM;\n+\t\t\tgoto err;\n+\t\t}\n+\n+\t/* need Max VF queues but already have default number of queues */\n+\tadq_request_qps = I40E_MAX_VF_QUEUES - I40E_DEFAULT_QUEUES_PER_VF;\n+\n+\tif (pf->queues_left < adq_request_qps) {\n+\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\"No queues left to allocate to VF %d\\n\",\n+\t\t\tvf->vf_id);\n+\t\taq_ret = I40E_ERR_PARAM;\n+\t\tgoto err;\n+\t} else {\n+\t\t/* we need to allocate max VF queues to enable ADq so as to\n+\t\t * make sure ADq enabled VF always gets back queues when it\n+\t\t * goes through a reset.\n+\t\t */\n+\t\tvf->num_queue_pairs = I40E_MAX_VF_QUEUES;\n+\t}\n+\n+\t/* parse data from the queue channel info */\n+\tvf->num_tc = tci->num_tc;\n+\tfor (i = 0; i < vf->num_tc; i++)\n+\t\tvf->ch[i].num_qps = tci->list[i].count;\n+\n+\t/* set this flag only after making sure all inputs are sane */\n+\tvf->adq_enabled = true;\n+\n+\t/* reset the VF in order to allocate resources */\n+\ti40e_vc_notify_vf_reset(vf);\n+\ti40e_reset_vf(vf, false);\n+\n+\treturn I40E_SUCCESS;\n+\n+\t/* send the response to the VF */\n+err:\n+\treturn i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_CHANNELS,\n+\t\t\t\t aq_ret);\n+}\n+\n /**\n * i40e_vc_process_vf_msg\n * @pf: pointer to the PF structure\n@@ -2816,7 +3107,9 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,\n \tcase VIRTCHNL_OP_REQUEST_QUEUES:\n \t\tret = i40e_vc_request_queues_msg(vf, msg, msglen);\n \t\tbreak;\n-\n+\tcase VIRTCHNL_OP_ENABLE_CHANNELS:\n+\t\tret = i40e_vc_add_qch_msg(vf, msg);\n+\t\tbreak;\n \tcase VIRTCHNL_OP_UNKNOWN:\n \tdefault:\n \t\tdev_err(&pf->pdev->dev, \"Unsupported opcode %d from VF %d\\n\",\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h\nindex 5efc4f92bb37..67543dbefcd8 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h\n@@ -69,6 +69,18 @@ enum i40e_vf_capabilities {\n \tI40E_VIRTCHNL_VF_CAP_IWARP,\n };\n \n+/* In ADq, max 4 VSI's can be allocated per VF including primary VF VSI.\n+ * These variables are used to store indices, id's and number of queues\n+ * for each VSI including that of primary VF VSI. Each Traffic class is\n+ * termed as channel and each channel can in-turn have 4 queues which\n+ * means max 16 queues overall per VF.\n+ */\n+struct i40evf_channel {\n+\tu16 vsi_idx; /* index in PF struct for all channel VSIs */\n+\tu16 vsi_id; /* VSI ID used by firmware */\n+\tu16 num_qps; /* number of queue pairs requested by user */\n+};\n+\n /* VF information structure */\n struct i40e_vf {\n \tstruct i40e_pf *pf;\n@@ -111,6 +123,11 @@ struct i40e_vf {\n \tu16 num_mac;\n \tu16 num_vlan;\n \n+\t/* ADq related variables */\n+\tbool adq_enabled; /* flag to enable adq */\n+\tu8 num_tc;\n+\tstruct i40evf_channel ch[I40E_MAX_VF_VSI];\n+\n \t/* RDMA Client */\n \tstruct virtchnl_iwarp_qvlist_info *qvlist_info;\n };\n", "prefixes": [ "04/12" ] }